Decompiled source of New Beginnings v1.0.1

BepInEx/plugins/NewBeginnings/NewBeginnings.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.1", FrameworkDisplayName = ".NET Framework 4.7.1")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace NewBeginnings
{
	internal static class BerthClearance
	{
		internal struct Footprint
		{
			internal Vector2 A;

			internal Vector2 B;

			internal float Radius;
		}

		private const float Margin = 1f;

		private const float MaximumSide = 12f;

		private const float MaximumRear = 4f;

		internal static Vector3 AdjustCrabBeach(ResolvedStart selected, Vector3 nativePosition)
		{
			//IL_002c: 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_0042: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: 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_0229: 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_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: 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)
			if (selected.Port.portIndex != 11 || !string.Equals(((Object)((Component)selected.Port).gameObject).name, "port E 11 crab beach", StringComparison.OrdinalIgnoreCase))
			{
				return nativePosition;
			}
			Transform boatPos = selected.Recovery.boatPos;
			Footprint own = ReadHull(selected.Body, nativePosition, boatPos.rotation);
			List<Footprint> list = new List<Footprint>();
			List<string> list2 = new List<string>();
			BoatMooringRopes[] array = Resources.FindObjectsOfTypeAll<BoatMooringRopes>();
			foreach (BoatMooringRopes val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Scene scene = ((Component)val).gameObject.scene;
				if (!((Scene)(ref scene)).IsValid())
				{
					continue;
				}
				scene = ((Component)val).gameObject.scene;
				if (!((Scene)(ref scene)).isLoaded || !((Component)val).gameObject.activeInHierarchy)
				{
					continue;
				}
				Rigidbody component = ((Component)val).GetComponent<Rigidbody>();
				SaveableObject component2 = ((Component)val).GetComponent<SaveableObject>();
				if ((Object)(object)component == (Object)null || (Object)(object)component == (Object)(object)selected.Body || (Object)(object)component2 == (Object)null)
				{
					continue;
				}
				if (RootHulls(component).Length != 1)
				{
					if (HasNearbyPhysicalBounds(component, own))
					{
						throw new InvalidOperationException("Crab Beach hull clearance could not measure nearby boat " + ((Object)component).name + ".");
					}
				}
				else
				{
					list.Add(ReadHull(component, ((Component)component).transform.position, ((Component)component).transform.rotation));
					list2.Add(((Object)component).name);
				}
			}
			Footprint[] others = list.ToArray();
			int closest;
			float num = MinimumGap(own, others, Vector2.zero, out closest);
			if (num >= 1f)
			{
				return nativePosition;
			}
			Vector3 dock = (selected.Recovery.mooringFront.position + selected.Recovery.mooringBack.position) * 0.5f;
			if (!TryDirections(boatPos.right, boatPos.forward, boatPos.position, dock, out var outward, out var rear))
			{
				throw new InvalidOperationException("Crab Beach hull clearance could not verify the direction away from the dock.");
			}
			if (!TryOffset(own, others, outward, rear, out var delta, out var side, out var back, out var gap))
			{
				throw new InvalidOperationException("Crab Beach hull clearance found no space within 12m sideways and 4m rearward; neighboring boats were left unchanged.");
			}
			Vector3 val2 = nativePosition + new Vector3(delta.x, 0f, delta.y);
			if (!Finite(val2))
			{
				throw new InvalidOperationException("Crab Beach hull clearance produced an invalid position.");
			}
			Plugin.Instance?.Report($"Crab Beach hull clearance: moved {side:F2}m away from dock and {back:F2}m rearward; blocker {list2[closest]}, capsule gap {num:F2}m -> {gap:F2}m. Dock and terrain clearance still require an in-game check.");
			return val2;
		}

		private static CapsuleCollider[] RootHulls(Rigidbody body)
		{
			return (from c in ((Component)body).GetComponents<CapsuleCollider>()
				where (Object)(object)c != (Object)null && ((Collider)c).enabled && !((Collider)c).isTrigger && (Object)(object)((Collider)c).attachedRigidbody == (Object)(object)body
				select c).ToArray();
		}

		private static Footprint ReadHull(Rigidbody body, Vector3 position, Quaternion rotation)
		{
			//IL_002a: 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_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)
			CapsuleCollider[] array = RootHulls(body);
			if (array.Length != 1)
			{
				throw new InvalidOperationException("Crab Beach hull clearance requires one measurable root capsule on " + ((Object)body).name + ".");
			}
			CapsuleCollider val = array[0];
			return MakeFootprint(position, rotation, ((Component)body).transform.lossyScale, val.center, val.radius, val.height, val.direction);
		}

		private static bool HasNearbyPhysicalBounds(Rigidbody body, Footprint own)
		{
			//IL_001a: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_00db: 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_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_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			float num = own.Radius + 1f + 12f + 4f;
			float num2 = Math.Min(own.A.x, own.B.x) - num;
			float num3 = Math.Max(own.A.x, own.B.x) + num;
			float num4 = Math.Min(own.A.y, own.B.y) - num;
			float num5 = Math.Max(own.A.y, own.B.y) + num;
			Collider[] componentsInChildren = ((Component)body).GetComponentsInChildren<Collider>();
			foreach (Collider val in componentsInChildren)
			{
				if (val.enabled && !val.isTrigger && !((Object)(object)val.attachedRigidbody != (Object)(object)body))
				{
					Bounds bounds = val.bounds;
					if (!Finite(((Bounds)(ref bounds)).min) || !Finite(((Bounds)(ref bounds)).max))
					{
						throw new InvalidOperationException("Crab Beach hull clearance found invalid collider bounds on " + ((Object)body).name + ".");
					}
					if (((Bounds)(ref bounds)).max.x >= num2 && ((Bounds)(ref bounds)).min.x <= num3 && ((Bounds)(ref bounds)).max.z >= num4 && ((Bounds)(ref bounds)).min.z <= num5)
					{
						return true;
					}
				}
			}
			return false;
		}

		internal static Footprint MakeFootprint(Vector3 position, Quaternion rotation, Vector3 scale, Vector3 center, float radius, float height, int direction)
		{
			//IL_0000: 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_0016: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: 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)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: 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_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: 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_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			if (!Finite(position) || !Finite(scale) || !Finite(center) || !Finite(rotation.x) || !Finite(rotation.y) || !Finite(rotation.z) || !Finite(rotation.w) || !Finite(radius) || !Finite(height) || radius <= 0f || height <= 0f || direction < 0 || direction > 2 || scale.x == 0f || scale.y == 0f || scale.z == 0f)
			{
				throw new InvalidOperationException("Crab Beach hull capsule has invalid geometry.");
			}
			Vector3 val = (Vector3)(direction switch
			{
				1 => Vector3.up, 
				0 => Vector3.right, 
				_ => Vector3.forward, 
			});
			float num = Math.Abs(((Vector3)(ref scale))[direction]);
			float num2 = Math.Max(Math.Abs(((Vector3)(ref scale))[(direction + 1) % 3]), Math.Abs(((Vector3)(ref scale))[(direction + 2) % 3]));
			float num3 = radius * num2;
			float num4 = Math.Max(0f, height * num * 0.5f - num3);
			Vector3 val2 = position + rotation * Vector3.Scale(center, scale);
			Vector3 val3 = rotation * val * num4;
			Vector3 val4 = val2 + val3;
			Vector3 val5 = val2 - val3;
			if (!Finite(val4) || !Finite(val5) || !Finite(num3) || num3 <= 0f)
			{
				throw new InvalidOperationException("Crab Beach hull capsule overflowed its geometry.");
			}
			return new Footprint
			{
				A = new Vector2(val4.x, val4.z),
				B = new Vector2(val5.x, val5.z),
				Radius = num3
			};
		}

		internal static bool TryDirections(Vector3 right, Vector3 forward, Vector3 marker, Vector3 dock, out Vector2 outward, out Vector2 rear)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0044: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_0095: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			outward = new Vector2(0f - right.x, 0f - right.z);
			rear = new Vector2(0f - forward.x, 0f - forward.z);
			if (!Finite(right) || !Finite(forward) || !Finite(marker) || !Finite(dock) || ((Vector2)(ref outward)).sqrMagnitude < 0.5f || ((Vector2)(ref rear)).sqrMagnitude < 0.5f)
			{
				return false;
			}
			((Vector2)(ref outward)).Normalize();
			((Vector2)(ref rear)).Normalize();
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(dock.x - marker.x, dock.z - marker.z);
			if (((Vector2)(ref val)).sqrMagnitude > 0.01f)
			{
				return Vector2.Dot(outward, ((Vector2)(ref val)).normalized) < -0.5f;
			}
			return false;
		}

		internal static bool TryOffset(Footprint own, Footprint[] others, Vector2 outward, Vector2 rear, out Vector2 delta, out float side, out float back, out float gap)
		{
			//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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0082: Unknown result type (might be due to invalid IL or missing references)
			delta = Vector2.zero;
			side = (back = 0f);
			gap = MinimumGap(own, others, delta, out var closest);
			if (gap >= 1f)
			{
				return true;
			}
			for (int i = 1; i <= 48; i++)
			{
				side = (float)i * 0.25f;
				back = Math.Min(side * 0.5f, 4f);
				delta = outward * side + rear * back;
				gap = MinimumGap(own, others, delta, out closest);
				if (gap >= 1f)
				{
					return true;
				}
			}
			return false;
		}

		internal static float MinimumGap(Footprint own, Footprint[] others, Vector2 delta, out int closest)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			float num = float.PositiveInfinity;
			closest = -1;
			for (int i = 0; i < others.Length; i++)
			{
				float num2 = SegmentDistance(own.A + delta, own.B + delta, others[i].A, others[i].B) - own.Radius - others[i].Radius;
				if (!Finite(num2))
				{
					throw new InvalidOperationException("Crab Beach hull clearance could not measure a finite gap between boats.");
				}
				if (num2 < num)
				{
					num = num2;
					closest = i;
				}
			}
			return num;
		}

		internal static float SegmentDistance(Vector2 p, Vector2 q, Vector2 r, Vector2 s)
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_0012: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: 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_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: 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_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)
			Vector2 val = q - p;
			Vector2 val2 = s - r;
			Vector2 val3 = p - r;
			double num = Vector2.Dot(val, val);
			double num2 = Vector2.Dot(val2, val2);
			double num3 = Vector2.Dot(val2, val3);
			if (num <= 1E-10 && num2 <= 1E-10)
			{
				return ((Vector2)(ref val3)).magnitude;
			}
			double num4;
			double num5;
			if (num <= 1E-10)
			{
				num4 = 0.0;
				num5 = Clamp(num3 / num2);
			}
			else
			{
				double num6 = Vector2.Dot(val, val3);
				if (num2 <= 1E-10)
				{
					num5 = 0.0;
					num4 = Clamp((0.0 - num6) / num);
				}
				else
				{
					double num7 = Vector2.Dot(val, val2);
					double num8 = num * num2 - num7 * num7;
					num4 = ((num8 > 1E-10) ? Clamp((num7 * num3 - num6 * num2) / num8) : 0.0);
					num5 = (num7 * num4 + num3) / num2;
					if (num5 < 0.0)
					{
						num5 = 0.0;
						num4 = Clamp((0.0 - num6) / num);
					}
					else if (num5 > 1.0)
					{
						num5 = 1.0;
						num4 = Clamp((num7 - num6) / num);
					}
				}
			}
			Vector2 val4 = p + val * (float)num4 - r - val2 * (float)num5;
			return ((Vector2)(ref val4)).magnitude;
		}

		private static double Clamp(double value)
		{
			return Math.Max(0.0, Math.Min(1.0, value));
		}

		private static bool Finite(Vector3 value)
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			if (Finite(value.x) && Finite(value.y))
			{
				return Finite(value.z);
			}
			return false;
		}

		private static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
	internal sealed class ResolvedStart
	{
		public Port Port;

		public RecoveryPort Recovery;

		public PurchasableBoat Boat;

		public SaveableObject Saveable;

		public Rigidbody Body;

		public BoatMooringRopes Ropes;

		public GPButtonDockMooring FrontMooring;

		public GPButtonDockMooring BackMooring;

		public StarterSet StarterSet;

		public StartMenu Menu;

		public int Region;

		public BoatSize? Size;
	}
	internal sealed class ProbeVelocityGuard
	{
		private readonly Component probes;

		private readonly FieldInfo field;

		private readonly bool previous;

		private bool restored;

		internal static bool CanGuard(SaveableObject boat)
		{
			Component val = (((Object)(object)boat != (Object)null) ? ((Component)boat).GetComponent("BoatProbes") : null);
			FieldInfo fieldInfo = (((Object)(object)val != (Object)null) ? AccessTools.Field(((object)val).GetType(), "dontUpdateVelocity") : null);
			if (fieldInfo != null)
			{
				return fieldInfo.FieldType == typeof(bool);
			}
			return false;
		}

		internal ProbeVelocityGuard(SaveableObject boat)
		{
			probes = ((Component)boat).GetComponent("BoatProbes");
			field = (((Object)(object)probes != (Object)null) ? AccessTools.Field(((object)probes).GetType(), "dontUpdateVelocity") : null);
			if (field == null || field.FieldType != typeof(bool))
			{
				throw new InvalidOperationException("Selected boat has no compatible BoatProbes velocity guard.");
			}
			previous = (bool)field.GetValue(probes);
			field.SetValue(probes, true);
		}

		internal void Restore()
		{
			if (restored)
			{
				return;
			}
			try
			{
				field.SetValue(probes, previous);
				restored = true;
			}
			catch (Exception exception)
			{
				Plugin.Instance?.Error("Could not restore the selected boat's velocity guard.", exception);
			}
		}
	}
	internal static class FixedStart
	{
		private sealed class RopePosition
		{
			public PickupableBoatMooringRope Rope;

			public Transform Parent;

			public Vector3 Position;

			public Quaternion Rotation;

			public GPButtonDockMooring Mooring;
		}

		private sealed class RopeCandidate
		{
			public PickupableBoatMooringRope Rope;

			public Vector3 LocalPosition;

			public float AlongHull;

			public float AcrossHull;
		}

		[HarmonyPatch(typeof(StartMenu), "ButtonClick", new Type[] { typeof(StartMenuButtonType) })]
		private static class ConfirmChoicePatch
		{
			private static bool Prefix(StartMenu __instance, StartMenuButtonType button)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Invalid comparison between Unknown and I4
				if ((int)button != 7)
				{
					return true;
				}
				ClearAcceptedButtonChoice();
				nativeFallbackButtonMenu = null;
				Plugin instance = Plugin.Instance;
				if ((Object)(object)instance == (Object)null || !ScrambledSeasIntegration.CanSelect)
				{
					return true;
				}
				MenuUi menuUi = null;
				try
				{
					menuUi = MenuUi.ActiveFor(__instance);
					if ((Object)(object)menuUi == (Object)null)
					{
						return true;
					}
					if (MenuAnimationsField?.GetValue(__instance) is int num && num > 0)
					{
						return true;
					}
					if (!menuUi.CanStart(out var reason))
					{
						menuUi.ShowBlockedStart(reason);
						instance.Warn("New game blocked by New Beginnings selection: " + reason);
						return false;
					}
					if (menuUi.CatalogUnavailable)
					{
						nativeFallbackButtonMenu = __instance;
						return true;
					}
					if (!instance.TryChooseStart(out var pair, out reason))
					{
						menuUi.ShowBlockedStart(reason);
						instance.Warn("New game blocked by New Beginnings selection: " + reason);
						return false;
					}
					acceptedButtonPair = pair;
					acceptedButtonMenu = __instance;
					return true;
				}
				catch (Exception exception)
				{
					ClearAcceptedButtonChoice();
					nativeFallbackButtonMenu = __instance;
					menuUi?.ShowCatalogUnavailable();
					instance.Error("New Beginnings selection failed; Sailwind's normal start will run.", exception);
					return true;
				}
			}

			private static void Postfix(StartMenu __instance)
			{
				if (acceptedButtonMenu == __instance)
				{
					ClearAcceptedButtonChoice();
				}
				if (nativeFallbackButtonMenu == __instance)
				{
					nativeFallbackButtonMenu = null;
				}
			}
		}

		[HarmonyPatch(typeof(StartMenu), "StartNewGame")]
		[HarmonyBefore(new string[] { "com.nandbrew.scrambledseas" })]
		private static class BeginPatch
		{
			private static void Prefix(StartMenu __instance)
			{
				//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ed: Expected I4, but got Unknown
				StartPair startPair = ((acceptedButtonMenu == __instance) ? acceptedButtonPair : null);
				bool flag = nativeFallbackButtonMenu == __instance;
				nativeFallbackButtonMenu = null;
				ClearAcceptedButtonChoice();
				pending = null;
				pendingMenu = null;
				nativeTweenObserver = null;
				nativeTweenTarget = null;
				Plugin.Instance?.CancelBoatSettle();
				LeopardStarterRig.Cancel();
				Plugin.Instance?.CancelPlayerStartTracking();
				Plugin.Instance?.ClearDocksideSurface();
				StarterCargo.Disarm();
				Plugin instance = Plugin.Instance;
				if ((Object)(object)instance == (Object)null || !ScrambledSeasIntegration.CanSelect || flag)
				{
					return;
				}
				object value = null;
				bool flag2 = false;
				try
				{
					StartPair pair = startPair;
					if (pair == null && !instance.TryChooseStart(out pair, out var reason))
					{
						instance.Warn("New Beginnings skipped; vanilla new game will run. " + reason);
						return;
					}
					value = CurrentRegionField.GetValue(__instance);
					CurrentRegionField.SetValue(__instance, (int)pair.Port.Port.region);
					flag2 = true;
					pending = pair;
					pendingMenu = __instance;
					instance.Report($"New Beginnings selected port {pair.Port.Index} and boat scene {pair.Boat.Index}.");
				}
				catch (Exception exception)
				{
					pending = null;
					pendingMenu = null;
					if (flag2)
					{
						try
						{
							CurrentRegionField.SetValue(__instance, value);
						}
						catch (Exception exception2)
						{
							instance.Error("Native start region could not be restored after selection failed.", exception2);
						}
					}
					instance.Error("New Beginnings selection failed; vanilla new game will run.", exception);
				}
			}
		}

		[HarmonyPatch(typeof(StartMenu), "StartNewGame")]
		private static class EndPatch
		{
			private static void Postfix(StartMenu __instance)
			{
				if (pendingMenu == __instance)
				{
					pending = null;
					pendingMenu = null;
					Plugin.Instance?.Warn("New Beginnings selection was cleared because no player-start coroutine was created.");
				}
			}
		}

		[HarmonyPatch(typeof(StartMenu), "MovePlayerToStartPos")]
		private static class StartPositionPatch
		{
			private static void Prefix(StartMenu __instance, ref Transform startPos)
			{
				Transform observer;
				GameObject controller;
				if (!nativeTweenSeamReady)
				{
					if (pending != null && __instance == pendingMenu)
					{
						pending = null;
						pendingMenu = null;
						Plugin.Instance?.Warn("New Beginnings skipped this native start because its camera tween seam was not verified; the regional game start will run.");
					}
				}
				else if (pending != null && __instance == pendingMenu && !TryGetNativeStartActors(__instance, out observer, out controller))
				{
					pending = null;
					pendingMenu = null;
					Plugin.Instance?.Warn("New Beginnings skipped this native start because its observer or controller is unavailable; the regional game start will run.");
				}
				else if (ApplyPendingAtStart(__instance, ref startPos))
				{
					TeleportNativeStartObserver(__instance, startPos);
				}
			}
		}

		[HarmonyPatch]
		private static class NativeStartTweenPatch
		{
			private static MethodBase targetMethod;

			private static bool Prepare()
			{
				nativeTweenSeamReady = false;
				try
				{
					MethodInfo methodInfo = AccessTools.Method(typeof(StartMenu), "MovePlayerToStartPos", new Type[1] { typeof(Transform) }, (Type[])null);
					targetMethod = ((methodInfo != null) ? AccessTools.EnumeratorMoveNext((MethodBase)methodInfo) : null);
				}
				catch (Exception ex)
				{
					targetMethod = null;
					Plugin.Instance?.Warn("Native player-start iterator could not be inspected: " + ex.Message);
				}
				if (targetMethod != null)
				{
					return true;
				}
				Plugin.Instance?.Warn("Native player-start iterator is unavailable; the selected-port camera seam is disabled for this Sailwind build.");
				return false;
			}

			private static MethodBase TargetMethod()
			{
				return targetMethod;
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> source)
			{
				//IL_0216: Unknown result type (might be due to invalid IL or missing references)
				//IL_0220: Expected O, but got Unknown
				MethodInfo original = AccessTools.Method(typeof(Juicebox), "TweenPosition", new Type[4]
				{
					typeof(GameObject),
					typeof(Vector3),
					typeof(float),
					typeof(JuiceboxTween)
				}, (Type[])null);
				MethodInfo methodInfo = AccessTools.Method(typeof(FixedStart), "NativeStartTweenOrSnap", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(FixedStart), "NativeStartAnimationSeconds", (Type[])null, (Type[])null);
				List<CodeInstruction> list = source.ToList();
				CodeInstruction[] array = list.Where((CodeInstruction instruction) => (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && object.Equals(instruction.operand, original)).ToArray();
				List<int> list2 = new List<int>();
				for (int num = 0; num < list.Count - 1; num++)
				{
					if (!(list[num].opcode != OpCodes.Ldc_R4) && list[num].operand is float num2 && (num2 == 7f || num2 == 1f) && !(list[num + 1].opcode != OpCodes.Stfld) && list[num + 1].operand is FieldInfo fieldInfo && fieldInfo.Name.Contains("<animTime>"))
					{
						list2.Add(num);
					}
				}
				if (original == null || methodInfo == null || methodInfo2 == null || array.Length != 1 || list2.Count != 2)
				{
					nativeTweenSeamReady = false;
					Plugin.Instance?.Warn("Native start tween and timing calls could not be isolated; Sailwind's original camera movement remains active.");
					return list;
				}
				array[0].opcode = OpCodes.Call;
				array[0].operand = methodInfo;
				foreach (int item in list2.OrderByDescending((int value) => value))
				{
					list.Insert(item + 1, new CodeInstruction(OpCodes.Call, (object)methodInfo2));
				}
				nativeTweenSeamReady = true;
				return list;
			}
		}

		private static readonly FieldInfo CurrentRegionField = AccessTools.Field(typeof(StartMenu), "currentRegion");

		private static readonly FieldInfo StartingBoatsField = AccessTools.Field(typeof(StartMenu), "startingBoats");

		private static readonly FieldInfo SaveableField = AccessTools.Field(typeof(PurchasableBoat), "saveable");

		private static readonly FieldInfo PurchaseUiField = AccessTools.Field(typeof(PurchasableBoat), "purchaseUI");

		private static readonly FieldInfo MooredSpringField = AccessTools.Field(typeof(PickupableBoatMooringRope), "mooredToSpring");

		private static readonly FieldInfo RecoveryPortsField = AccessTools.Field(typeof(Recovery), "ports");

		private static readonly FieldInfo PlayerObserverField = AccessTools.Field(typeof(StartMenu), "playerObserver");

		private static readonly FieldInfo PlayerControllerField = AccessTools.Field(typeof(StartMenu), "playerController");

		private static readonly FieldInfo MenuAnimationsField = AccessTools.Field(typeof(StartMenu), "animsPlaying");

		private static StartPair pending;

		private static StartMenu pendingMenu;

		private static StartPair acceptedButtonPair;

		private static StartMenu acceptedButtonMenu;

		private static StartMenu nativeFallbackButtonMenu;

		private static GameObject nativeTweenObserver;

		private static Transform nativeTweenTarget;

		private static bool nativeTweenSeamReady;

		private static void ClearAcceptedButtonChoice()
		{
			acceptedButtonPair = null;
			acceptedButtonMenu = null;
		}

		internal static bool TryGetNativeStartActors(StartMenu menu, out Transform observer, out GameObject controller)
		{
			observer = null;
			controller = null;
			try
			{
				object? obj = PlayerObserverField?.GetValue(menu);
				observer = (Transform)((obj is Transform) ? obj : null);
				object? obj2 = PlayerControllerField?.GetValue(menu);
				controller = (GameObject)((obj2 is GameObject) ? obj2 : null);
				return (Object)(object)observer != (Object)null && (Object)(object)controller != (Object)null;
			}
			catch (Exception exception)
			{
				Plugin.Instance?.Error("Native start actor fields could not be read.", exception);
				return false;
			}
		}

		private static float NativeStartAnimationSeconds(float vanillaSeconds)
		{
			if (!((Object)(object)nativeTweenObserver != (Object)null))
			{
				return vanillaSeconds;
			}
			return 0f;
		}

		private static void NativeStartTweenOrSnap(Juicebox tween, GameObject observer, Vector3 destination, float duration, JuiceboxTween easing)
		{
			//IL_0081: 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_0032: 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)
			if ((Object)(object)nativeTweenObserver != (Object)null && (Object)(object)observer == (Object)(object)nativeTweenObserver)
			{
				if ((Object)(object)nativeTweenTarget != (Object)null)
				{
					observer.transform.SetPositionAndRotation(nativeTweenTarget.position, nativeTweenTarget.rotation);
				}
				else
				{
					Plugin.Instance?.Warn("Selected player marker disappeared before the native camera tween; preserving the already teleported observer position.");
				}
				Plugin.Instance?.Report("Suppressed native new-game camera tween for the selected port.");
				nativeTweenObserver = null;
				nativeTweenTarget = null;
			}
			else
			{
				tween.TweenPosition(observer, destination, duration, easing);
			}
		}

		internal static bool ApplyPendingAtStart(StartMenu menu, ref Transform startPos)
		{
			if (pending == null || menu != pendingMenu)
			{
				return false;
			}
			StartPair startPair = pending;
			pending = null;
			pendingMenu = null;
			try
			{
				if (!TryResolve(startPair.Port.Index, startPair.Boat.Index, out var result, out var reason) || result.Port != startPair.Port.Port || result.Recovery != startPair.Port.Recovery || result.Boat != startPair.Boat.Boat || result.Saveable != startPair.Boat.Saveable)
				{
					Plugin.Instance.Warn("New Beginnings placement skipped; the regional game start will run. " + (reason ?? "Selected boat or berth changed after catalog discovery."));
					return false;
				}
				result.Size = startPair.Boat.Size;
				Apply(result, menu, ref startPos);
				return true;
			}
			catch (Exception exception)
			{
				Plugin.Instance.Error("New Beginnings placement failed; the regional game start remains selected where possible.", exception);
				return false;
			}
		}

		private static void TeleportNativeStartObserver(StartMenu menu, Transform target)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_0059: 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)
			try
			{
				if (!TryGetNativeStartActors(menu, out var observer, out var controller) || (Object)(object)target == (Object)null || !IsFinite(target.position) || !IsFinite(target.rotation))
				{
					Plugin.Instance.Warn("Native start observer or target is unavailable; Sailwind's normal camera movement will run.");
					return;
				}
				observer.SetPositionAndRotation(target.position, target.rotation);
				controller.transform.SetPositionAndRotation(target.position, target.rotation);
				nativeTweenObserver = ((Component)observer).gameObject;
				nativeTweenTarget = target;
				Plugin.Instance.Report("Native new-game observer and controller moved directly to the selected port.");
			}
			catch (Exception exception)
			{
				Plugin.Instance.Error("Could not move the native start camera directly; Sailwind's normal camera movement will run.", exception);
			}
		}

		private static bool IsFinite(Vector3 value)
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			if (IsFinite(value.x) && IsFinite(value.y))
			{
				return IsFinite(value.z);
			}
			return false;
		}

		private static bool IsFinite(Quaternion value)
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (IsFinite(value.x) && IsFinite(value.y) && IsFinite(value.z))
			{
				return IsFinite(value.w);
			}
			return false;
		}

		private static bool IsFinite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		internal static bool IsPairViable(PortChoice port, BoatChoice boat)
		{
			if ((Object)(object)port?.Port == (Object)null || (Object)(object)port.Recovery == (Object)null || (Object)(object)boat?.Boat == (Object)null || (Object)(object)boat.Saveable == (Object)null || (Object)(object)port.Recovery.parentPort != (Object)(object)port.Port || (Object)(object)port.Recovery.boatPos == (Object)null || (Object)(object)port.Recovery.mooringFront == (Object)null || (Object)(object)port.Recovery.mooringBack == (Object)null || boat.Boat.isPurchased())
			{
				return false;
			}
			Rigidbody component = ((Component)boat.Saveable).GetComponent<Rigidbody>();
			BoatMooringRopes component2 = ((Component)boat.Saveable).GetComponent<BoatMooringRopes>();
			GPButtonDockMooring front = ((Component)port.Recovery.mooringFront).GetComponent<GPButtonDockMooring>();
			GPButtonDockMooring back = ((Component)port.Recovery.mooringBack).GetComponent<GPButtonDockMooring>();
			if ((Object)(object)component == (Object)null || !ProbeVelocityGuard.CanGuard(boat.Saveable) || (Object)(object)component2 == (Object)null || component2.ropes == null || component2.ropes.Length < 2 || component2.ropes.Any((PickupableBoatMooringRope item) => (Object)(object)item == (Object)null) || (Object)(object)component2.GetAnchorController() == (Object)null || ((Object)(object)component2.anchor != (Object)null && component2.anchor.IsSet()) || (Object)(object)front == (Object)null || (Object)(object)back == (Object)null || (Object)(object)front == (Object)(object)back || (Object)(object)front.spring == (Object)null || (Object)(object)back.spring == (Object)null)
			{
				return false;
			}
			if (SirenSongBerth.IsTarget(port.Port) && !SirenSongBerth.TryGetMoorings(port.Port, port.Recovery, component, out front, out back, out var _))
			{
				return false;
			}
			if ((Object)(object)((Joint)front.spring).connectedBody == (Object)null || (Object)(object)((Joint)front.spring).connectedBody == (Object)(object)component)
			{
				if (!((Object)(object)((Joint)back.spring).connectedBody == (Object)null))
				{
					return (Object)(object)((Joint)back.spring).connectedBody == (Object)(object)component;
				}
				return true;
			}
			return false;
		}

		private static bool TryResolve(int portIndex, int boatSceneIndex, out ResolvedStart result, out string reason)
		{
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Expected I4, but got Unknown
			//IL_039b: Unknown result type (might be due to invalid IL or missing references)
			result = null;
			reason = null;
			Port[] ports = Port.ports;
			if (ports == null || portIndex < 0 || portIndex >= ports.Length || (Object)(object)ports[portIndex] == (Object)null || ports[portIndex].portIndex != portIndex)
			{
				reason = $"Port {portIndex} is not registered.";
				return false;
			}
			Port port = ports[portIndex];
			if (portIndex == 7 && string.Equals(((Object)((Component)port).gameObject).name, "port 7 (test port)", StringComparison.OrdinalIgnoreCase))
			{
				reason = "The scene test port is not a playable start.";
				return false;
			}
			RecoveryPort val = (RecoveryPortsField.GetValue(null) as List<RecoveryPort>)?.FirstOrDefault((Func<RecoveryPort, bool>)((RecoveryPort item) => (Object)(object)item != (Object)null && (Object)(object)item.parentPort == (Object)(object)port && (Object)(object)item.boatPos != (Object)null && (Object)(object)item.mooringFront != (Object)null && (Object)(object)item.mooringBack != (Object)null));
			if ((Object)(object)val == (Object)null)
			{
				reason = $"Port {portIndex} has no complete registered recovery berth.";
				return false;
			}
			GPButtonDockMooring front = ((Component)val.mooringFront).GetComponent<GPButtonDockMooring>();
			GPButtonDockMooring back = ((Component)val.mooringBack).GetComponent<GPButtonDockMooring>();
			if ((Object)(object)front == (Object)null || (Object)(object)back == (Object)null || (Object)(object)front == (Object)(object)back || (Object)(object)front.spring == (Object)null || (Object)(object)back.spring == (Object)null)
			{
				reason = $"Port {portIndex} has no initialized pair of dock springs.";
				return false;
			}
			var array = (from item in Resources.FindObjectsOfTypeAll<PurchasableBoat>().Where(delegate(PurchasableBoat item)
				{
					//IL_0017: Unknown result type (might be due to invalid IL or missing references)
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					if ((Object)(object)item != (Object)null && ((Behaviour)item).enabled)
					{
						Scene scene = ((Component)item).gameObject.scene;
						if (((Scene)(ref scene)).isLoaded)
						{
							return ((Component)item).gameObject.activeInHierarchy;
						}
					}
					return false;
				}).Select(delegate(PurchasableBoat item)
				{
					object? value2 = SaveableField.GetValue(item);
					return new
					{
						Boat = item,
						Saveable = (SaveableObject)((value2 is SaveableObject) ? value2 : null)
					};
				})
				where (Object)(object)item.Saveable != (Object)null && item.Saveable.sceneIndex == boatSceneIndex && SelectionCatalog.IsBoatLike(item.Saveable)
				select item).ToArray();
			if (array.Length != 1)
			{
				reason = $"Boat scene index {boatSceneIndex} resolved to {array.Length} candidates; expected exactly one.";
				return false;
			}
			PurchasableBoat boat = array[0].Boat;
			SaveableObject saveable = array[0].Saveable;
			object? value = PurchaseUiField.GetValue(boat);
			if ((Object)((value is GameObject) ? value : null) == (Object)null || boat.isPurchased())
			{
				reason = $"Boat {boatSceneIndex} lacks its normal purchase UI or is already purchased.";
				return false;
			}
			Rigidbody component = ((Component)saveable).GetComponent<Rigidbody>();
			BoatMooringRopes component2 = ((Component)saveable).GetComponent<BoatMooringRopes>();
			if ((Object)(object)component == (Object)null || !ProbeVelocityGuard.CanGuard(saveable) || (Object)(object)component2 == (Object)null || component2.ropes == null || component2.ropes.Length < 2 || component2.ropes.Any((PickupableBoatMooringRope item) => (Object)(object)item == (Object)null) || (Object)(object)component2.GetAnchorController() == (Object)null)
			{
				reason = $"Boat {boatSceneIndex} lacks its normal rigidbody, velocity guard, mooring ropes, or anchor controller.";
				return false;
			}
			if (SirenSongBerth.IsTarget(port) && !SirenSongBerth.TryGetMoorings(port, val, component, out front, out back, out reason))
			{
				return false;
			}
			if (((Object)(object)((Joint)front.spring).connectedBody != (Object)null && (Object)(object)((Joint)front.spring).connectedBody != (Object)(object)component) || ((Object)(object)((Joint)back.spring).connectedBody != (Object)null && (Object)(object)((Joint)back.spring).connectedBody != (Object)(object)component))
			{
				reason = $"Port {portIndex} has a dock spring occupied by another boat.";
				return false;
			}
			if ((Object)(object)component2.anchor != (Object)null && component2.anchor.IsSet())
			{
				reason = $"Boat {boatSceneIndex} is anchored; this fixed-start stage cannot safely restore that state on failure.";
				return false;
			}
			int region = (int)port.region;
			if (region < 0 || region > 2)
			{
				reason = $"Port {portIndex} has unsupported region {port.region}.";
				return false;
			}
			StarterSet[] array2 = Resources.FindObjectsOfTypeAll<StarterSet>().Where(delegate(StarterSet item)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Invalid comparison between Unknown and I4
				if ((Object)(object)item != (Object)null)
				{
					Scene scene = ((Component)item).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						return (int)item.region == region;
					}
				}
				return false;
			}).ToArray();
			if (array2.Length != 1)
			{
				reason = $"Region {region} has {array2.Length} starter sets; expected exactly one.";
				return false;
			}
			result = new ResolvedStart
			{
				Port = port,
				Recovery = val,
				Boat = boat,
				Saveable = saveable,
				Body = component,
				Ropes = component2,
				FrontMooring = front,
				BackMooring = back,
				StarterSet = array2[0],
				Region = region
			};
			return true;
		}

		private static void Apply(ResolvedStart selected, StartMenu menu, ref Transform startPos)
		{
			//IL_0015: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0519: Unknown result type (might be due to invalid IL or missing references)
			//IL_0526: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0049: 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_004f: 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_0064: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0539: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05be: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c5: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: 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_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: 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_03ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_047f: Unknown result type (might be due to invalid IL or missing references)
			SirenSongBerth.Plan plan;
			bool flag = SirenSongBerth.TryCreate(selected, out plan);
			Vector3 position = (flag ? plan.Position : GetBerthPosition(selected));
			if (flag)
			{
				selected.FrontMooring = plan.Front;
				selected.BackMooring = plan.Back;
			}
			Quaternion rotation = selected.Recovery.boatPos.rotation;
			position = AdjustLargeBoatBerth(selected, position, rotation);
			Transform transform = ((Component)selected.Saveable).transform;
			Vector3 position2 = transform.position;
			Quaternion rotation2 = transform.rotation;
			if (!IsFinite(((Component)selected.Port).transform.position) || !IsFinite(((Component)selected.Recovery).transform.position) || !IsFinite(selected.Recovery.boatPos.position) || !IsFinite(position) || !IsFinite(rotation) || !IsFinite(position2) || !IsFinite(rotation2))
			{
				throw new InvalidOperationException("A selected port, berth or boat has a non-finite transform.");
			}
			Plugin.Instance.Report($"Start placement coordinates: port {((Component)selected.Port).transform.position}, recovery dock marker {((Component)selected.Recovery).transform.position}, berth {position}, boat origin {position2}.");
			Vector3 velocity = selected.Body.velocity;
			Vector3 angularVelocity = selected.Body.angularVelocity;
			Anchor anchor = selected.Ropes.anchor;
			Rigidbody val = (((Object)(object)anchor != (Object)null) ? ((Component)anchor).GetComponent<Rigidbody>() : null);
			Vector3 val2 = (((Object)(object)val != (Object)null) ? val.position : Vector3.zero);
			float num = (((Object)(object)anchor != (Object)null) ? anchor.GetRopeLength() : 0f);
			PurchasableBoat[] array = (PurchasableBoat[])StartingBoatsField.GetValue(menu);
			if (array == null || selected.Region >= array.Length || (Object)(object)array[selected.Region] == (Object)null)
			{
				throw new InvalidOperationException("Native regional starting boat array is incomplete.");
			}
			Transform starterBoat = selected.StarterSet.starterBoat;
			Transform lastBoat = GameState.lastBoat;
			Transform lastOwnedBoat = GameState.lastOwnedBoat;
			Port lastVisitedPort = GameState.lastVisitedPort;
			Transform val3 = startPos;
			RopePosition[] array2 = selected.Ropes.ropes.Select((PickupableBoatMooringRope rope) => new RopePosition
			{
				Rope = rope,
				Parent = ((Component)rope).transform.parent,
				Position = ((Component)rope).transform.position,
				Rotation = ((Component)rope).transform.rotation,
				Mooring = GetOriginalMooring(rope)
			}).ToArray();
			bool flag2 = false;
			ProbeVelocityGuard probeVelocityGuard = null;
			try
			{
				probeVelocityGuard = new ProbeVelocityGuard(selected.Saveable);
				selected.Ropes.UnmoorAllRopes();
				selected.Ropes.GetAnchorController().ResetAnchor();
				flag2 = true;
				transform.SetPositionAndRotation(position, rotation);
				selected.Body.position = position;
				selected.Body.rotation = rotation;
				selected.Body.velocity = Vector3.zero;
				selected.Body.angularVelocity = Vector3.zero;
				if ((Object)(object)val != (Object)null)
				{
					val.position = val2 + (position - position2);
					val.velocity = Vector3.zero;
					val.angularVelocity = Vector3.zero;
				}
				if (!IsFinite(transform.position) || !IsFinite(selected.Body.position) || ((Object)(object)val != (Object)null && !IsFinite(val.position)))
				{
					throw new InvalidOperationException("Boat or anchor gained a non-finite position during placement.");
				}
				Physics.SyncTransforms();
				ChooseMooringRopes(selected, out var front, out var back);
				MoorAt(front, selected.FrontMooring, selected.Body);
				MoorAt(back, selected.BackMooring, selected.Body);
				PurchasableBoat[] array3 = (PurchasableBoat[])array.Clone();
				array3[selected.Region] = selected.Boat;
				Transform val4 = Plugin.Instance.MakeTemporaryStart(selected, selected.Recovery.boatPos.rotation, flag ? new Vector3?(plan.ShorePosition) : ((Vector3?)null), position);
				if (!IsFinite(val4.position) || !IsFinite(val4.rotation))
				{
					throw new InvalidOperationException("Selected player target gained a non-finite transform.");
				}
				StartingBoatsField.SetValue(menu, array3);
				selected.StarterSet.starterBoat = transform;
				GameState.lastBoat = transform;
				GameState.lastOwnedBoat = transform;
				GameState.lastVisitedPort = selected.Port;
				startPos = val4;
				selected.Menu = menu;
				Plugin.Instance.BeginPlayerStartTracking(menu, val4);
				StarterCargo.Arm(selected);
				StarterMooring.Arm(menu, selected, front, back);
				Plugin.Instance.Report($"Placed boat {selected.Saveable.sceneIndex} at port {selected.Port.portIndex}; native new-game ownership grant will follow.");
				Plugin.Instance.BeginBoatSettle(menu, selected, position, rotation, probeVelocityGuard);
				probeVelocityGuard = null;
				StarterBoatRepair.Arm(menu, selected);
				LeopardStarterRig.Arm(menu, selected);
			}
			catch
			{
				try
				{
					StartingBoatsField.SetValue(menu, array);
					selected.StarterSet.starterBoat = starterBoat;
					GameState.lastBoat = lastBoat;
					GameState.lastOwnedBoat = lastOwnedBoat;
					GameState.lastVisitedPort = lastVisitedPort;
					startPos = val3;
					Plugin.Instance.CancelPlayerStartTracking();
					StarterCargo.Disarm();
					StarterMooring.Cancel();
					StarterBoatRepair.Cancel();
					if (flag2)
					{
						transform.SetPositionAndRotation(position2, rotation2);
						selected.Body.position = position2;
						selected.Body.rotation = rotation2;
						selected.Body.velocity = velocity;
						selected.Body.angularVelocity = angularVelocity;
						if ((Object)(object)val != (Object)null)
						{
							val.position = val2;
						}
						if ((Object)(object)anchor != (Object)null)
						{
							anchor.OnLoad(false, num);
						}
					}
					RopePosition[] array4 = array2;
					foreach (RopePosition ropePosition in array4)
					{
						try
						{
							ropePosition.Rope.Unmoor();
							if ((Object)(object)ropePosition.Mooring != (Object)null)
							{
								ropePosition.Rope.MoorTo(ropePosition.Mooring);
								continue;
							}
							((Component)ropePosition.Rope).transform.SetParent(ropePosition.Parent, true);
							((Component)ropePosition.Rope).transform.SetPositionAndRotation(ropePosition.Position, ropePosition.Rotation);
						}
						catch (Exception ex)
						{
							Plugin.Instance.Warn("A rope could not be restored after failed placement: " + ex.Message);
						}
					}
				}
				finally
				{
					probeVelocityGuard?.Restore();
				}
				throw;
			}
		}

		private static GPButtonDockMooring GetOriginalMooring(PickupableBoatMooringRope rope)
		{
			if (!rope.IsMoored())
			{
				return null;
			}
			object? value = MooredSpringField.GetValue(rope);
			SpringJoint val = (SpringJoint)((value is SpringJoint) ? value : null);
			GPButtonDockMooring val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<GPButtonDockMooring>() : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.spring != (Object)(object)val)
			{
				throw new InvalidOperationException("An existing mooring rope has no recoverable dock spring.");
			}
			return val2;
		}

		private static void ChooseMooringRopes(ResolvedStart selected, out PickupableBoatMooringRope front, out PickupableBoatMooringRope back)
		{
			//IL_0218: 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_0232: 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_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0500: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			RopeCandidate[] array = selected.Ropes.ropes.Select((PickupableBoatMooringRope rope) => new RopeCandidate
			{
				Rope = rope,
				LocalPosition = ((Component)selected.Saveable).transform.InverseTransformPoint(((Component)rope).transform.position)
			}).ToArray();
			LogHappyBayMooringGeometry(selected, array);
			float num = array.Max((RopeCandidate item) => item.LocalPosition.x) - array.Min((RopeCandidate item) => item.LocalPosition.x);
			float num2 = array.Max((RopeCandidate item) => item.LocalPosition.z) - array.Min((RopeCandidate item) => item.LocalPosition.z);
			bool flag = num > num2;
			RopeCandidate[] array2 = array;
			foreach (RopeCandidate ropeCandidate in array2)
			{
				ropeCandidate.AlongHull = (flag ? ropeCandidate.LocalPosition.x : ropeCandidate.LocalPosition.z);
				ropeCandidate.AcrossHull = (flag ? ropeCandidate.LocalPosition.z : ropeCandidate.LocalPosition.x);
			}
			float minimum = array.Min((RopeCandidate item) => item.AlongHull);
			float maximum = array.Max((RopeCandidate item) => item.AlongHull);
			float num4 = array.Min((RopeCandidate item) => item.AcrossHull);
			float num5 = array.Max((RopeCandidate item) => item.AcrossHull);
			float num6 = (num4 + num5) * 0.5f;
			float num7 = Mathf.Max(0.1f, (num5 - num4) * 0.1f);
			Vector3 val = (((Component)selected.FrontMooring).transform.position + ((Component)selected.BackMooring).transform.position) * 0.5f;
			Vector3 val2 = ((Component)selected.Saveable).transform.InverseTransformPoint(val);
			float num8 = (flag ? val2.z : val2.x) - num6;
			float endTolerance = Mathf.Max(0.15f, (maximum - minimum) * 0.12f);
			RopeCandidate[] array3 = array.Where((RopeCandidate item) => item.AlongHull <= minimum + endTolerance).ToArray();
			RopeCandidate[] array4 = array.Where((RopeCandidate item) => item.AlongHull >= maximum - endTolerance).ToArray();
			float num9 = float.PositiveInfinity;
			int num10 = int.MaxValue;
			RopeCandidate ropeCandidate2 = null;
			RopeCandidate ropeCandidate3 = null;
			array2 = array3;
			foreach (RopeCandidate ropeCandidate4 in array2)
			{
				RopeCandidate[] array5 = array4;
				foreach (RopeCandidate ropeCandidate5 in array5)
				{
					if (!((Object)(object)ropeCandidate4.Rope == (Object)(object)ropeCandidate5.Rope))
					{
						float num12 = ropeCandidate4.AcrossHull - num6;
						float num13 = ropeCandidate5.AcrossHull - num6;
						bool num14 = (num12 > num7 && num13 < 0f - num7) || (num12 < 0f - num7 && num13 > num7);
						float num15 = num12 + num13;
						bool flag2 = Mathf.Abs(num8) > num7 && num15 * num8 > num7 * num7;
						int num16 = (num14 ? 2 : ((!flag2) ? 1 : 0));
						float num17 = HorizontalDistanceSquared(((Component)ropeCandidate4.Rope).transform.position, ((Component)selected.FrontMooring).transform.position);
						float num18 = HorizontalDistanceSquared(((Component)ropeCandidate4.Rope).transform.position, ((Component)selected.BackMooring).transform.position);
						float num19 = HorizontalDistanceSquared(((Component)ropeCandidate5.Rope).transform.position, ((Component)selected.FrontMooring).transform.position);
						float num20 = HorizontalDistanceSquared(((Component)ropeCandidate5.Rope).transform.position, ((Component)selected.BackMooring).transform.position);
						if (num16 < num10 || (num16 == num10 && num17 + num20 < num9))
						{
							num10 = num16;
							num9 = num17 + num20;
							ropeCandidate2 = ropeCandidate4;
							ropeCandidate3 = ropeCandidate5;
						}
						if (num16 < num10 || (num16 == num10 && num19 + num18 < num9))
						{
							num10 = num16;
							num9 = num19 + num18;
							ropeCandidate2 = ropeCandidate5;
							ropeCandidate3 = ropeCandidate4;
						}
					}
				}
			}
			if (ropeCandidate2 == null || ropeCandidate3 == null)
			{
				throw new InvalidOperationException("Selected boat has no distinct mooring ropes at opposite ends.");
			}
			front = ropeCandidate2.Rope;
			back = ropeCandidate3.Rope;
			Plugin.Instance.Report($"Start mooring ropes: front {((Object)front).name} at {ropeCandidate2.LocalPosition}, back {((Object)back).name} at {ropeCandidate3.LocalPosition}; " + string.Format("longitudinal axis {0} span {1:0.00} m; ", flag ? "X" : "Z", maximum - minimum) + $"dock lateral offset {num8:0.00} m, rope lateral center {num6:0.00} m; " + string.Format("{0}, horizontal distance squared {1:0.00}.", num10 switch
			{
				0 => "dock-facing same-side pair", 
				2 => "mixed-side fallback", 
				_ => "same-side pair", 
			}, num9));
		}

		private static float HorizontalDistanceSquared(Vector3 rope, Vector3 dock)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			float num = rope.x - dock.x;
			float num2 = rope.z - dock.z;
			return num * num + num2 * num2;
		}

		private static void LogHappyBayMooringGeometry(ResolvedStart selected, RopeCandidate[] candidates)
		{
			//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)
			//IL_00e7: 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_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			if (selected.Saveable.sceneIndex != 144 || !string.Equals(((Object)((Component)selected.Saveable).gameObject).name, "BOAT happybayboat (144)(Clone)", StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			try
			{
				Transform transform = ((Component)selected.Saveable).transform;
				Transform transform2 = ((Component)selected.FrontMooring).transform;
				Transform transform3 = ((Component)selected.BackMooring).transform;
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					string[] obj = new string[19]
					{
						$"Happy Bay mooring diagnostic: port {selected.Port.portIndex}, hull {((Object)transform).name}; ",
						"front dock ",
						((Object)transform2).name,
						" [parent ",
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null,
						null
					};
					Transform parent = transform2.parent;
					obj[4] = ((parent != null) ? ((Object)parent).name : null);
					obj[5] = ", root ";
					obj[6] = ((Object)transform2.root).name;
					obj[7] = "] at hull-local ";
					Vector3 val = transform.InverseTransformPoint(transform2.position);
					obj[8] = ((Vector3)(ref val)).ToString("F3");
					obj[9] = "; back dock ";
					obj[10] = ((Object)transform3).name;
					obj[11] = " [parent ";
					Transform parent2 = transform3.parent;
					obj[12] = ((parent2 != null) ? ((Object)parent2).name : null);
					obj[13] = ", root ";
					obj[14] = ((Object)transform3.root).name;
					obj[15] = "] at hull-local ";
					val = transform.InverseTransformPoint(transform3.position);
					obj[16] = ((Vector3)(ref val)).ToString("F3");
					obj[17] = "; ";
					obj[18] = $"registered ropes {candidates.Length}.";
					instance.Report(string.Concat(obj));
				}
				foreach (RopeCandidate item in candidates.Take(8))
				{
					Plugin.Instance?.Report("Happy Bay mooring diagnostic: rope " + ((Object)item.Rope).name + " " + string.Format("at hull-local {0}, selected body {1}, ", ((Vector3)(ref item.LocalPosition)).ToString("F3"), (Object)(object)item.Rope.GetBoatRigidbody() == (Object)(object)selected.Body) + $"front horizontal distance squared {HorizontalDistanceSquared(((Component)item.Rope).transform.position, transform2.position):F3}, " + $"back horizontal distance squared {HorizontalDistanceSquared(((Component)item.Rope).transform.position, transform3.position):F3}.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance?.Warn("Happy Bay mooring diagnostic was unavailable: " + ex.Message);
			}
		}

		private static void MoorAt(PickupableBoatMooringRope rope, GPButtonDockMooring dock, Rigidbody body)
		{
			if ((Object)(object)((Joint)dock.spring).connectedBody != (Object)null)
			{
				throw new InvalidOperationException("Dock spring became occupied during boat placement.");
			}
			if ((Object)(object)rope == (Object)null || rope.IsMoored())
			{
				throw new InvalidOperationException("Chosen mooring rope is unavailable.");
			}
			rope.MoorTo(dock);
			if (!rope.IsMoored() || (Object)(object)((Joint)dock.spring).connectedBody != (Object)(object)body)
			{
				throw new InvalidOperationException("Boat mooring did not connect to the selected hull.");
			}
		}

		internal static bool IsLeopardStart(ResolvedStart selected)
		{
			if ((Object)(object)selected?.Saveable != (Object)null)
			{
				return IsLeopardIdentity(selected.Saveable.sceneIndex, ((Object)selected.Saveable).name);
			}
			return false;
		}

		private static bool IsLeopardIdentity(int sceneIndex, string name)
		{
			if (sceneIndex == 207)
			{
				return name == "BOAT LEOPARD (207)(Clone)";
			}
			return false;
		}

		private static Vector3 AdjustLargeBoatBerth(ResolvedStart selected, Vector3 position, Quaternion rotation)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_009e: 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)
			float num = ExtraBerthDistance(IsLeopardStart(selected), selected.Size);
			if (num == 0f)
			{
				return position;
			}
			if (!TryOutwardOffset(rotation * Vector3.right, position, ((Component)selected.FrontMooring).transform.position, ((Component)selected.BackMooring).transform.position, num, out var delta))
			{
				Plugin.Instance.Warn("Large-boat extra berth distance skipped: the live dock-facing side could not be verified.");
				return position;
			}
			Vector3 val = position + delta;
			if (!IsFinite(val))
			{
				throw new InvalidOperationException("Large-boat berth offset produced a non-finite position.");
			}
			Plugin.Instance.Report($"Boat {selected.Saveable.sceneIndex} berth moved an extra {num:F2}m away from its live dock pair to {val}; existing berth adjustments and shore markers preserved.");
			return val;
		}

		private static float ExtraBerthDistance(bool leopard, BoatSize? size)
		{
			if (!leopard)
			{
				if (size != BoatSize.Large)
				{
					return 0f;
				}
				return 1f;
			}
			return 3f;
		}

		private static bool TryOutwardOffset(Vector3 right, Vector3 berth, Vector3 front, Vector3 back, float distance, out Vector3 delta)
		{
			//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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_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)
			//IL_00ad: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			delta = Vector3.zero;
			if (!IsFinite(right) || !IsFinite(berth) || !IsFinite(front) || !IsFinite(back) || float.IsNaN(distance) || float.IsInfinity(distance) || distance <= 0f)
			{
				return false;
			}
			right.y = 0f;
			if (((Vector3)(ref right)).sqrMagnitude < 0.5f)
			{
				return false;
			}
			((Vector3)(ref right)).Normalize();
			float num = Vector3.Dot((front + back) * 0.5f - berth, right);
			if (Mathf.Abs(num) < 0.5f)
			{
				return false;
			}
			if (float.IsNaN(num) || float.IsInfinity(num))
			{
				return false;
			}
			delta = right * ((num > 0f) ? (0f - distance) : distance);
			return IsFinite(delta);
		}

		private static Vector3 GetBerthPosition(ResolvedStart selected)
		{
			//IL_0033: 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_009d: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			Transform boatPos = selected.Recovery.boatPos;
			int mask = LayerMask.GetMask(new string[1] { "Ignore Raycast" });
			Collider[] array = (from collider in Physics.OverlapSphere(boatPos.position, 5f, mask)
				where (Object)(object)collider != (Object)null && ((Component)collider).CompareTag("Boat")
				select collider).ToArray();
			Vector3 nativePosition = ((array.Length != 0 && array.All((Collider collider) => (Object)(object)collider.attachedRigidbody == (Object)(object)selected.Body || ((Component)collider).transform.IsChildOf(((Component)selected.Saveable).transform))) ? boatPos.position : selected.Recovery.GetBoatPos());
			return BerthClearance.AdjustCrabBeach(selected, nativePosition);
		}

		internal static bool IsSelectionStillActive(StartMenu menu, ResolvedStart selected)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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)
			if (!((Object)(object)menu == (Object)null) && selected != null && !((Object)(object)selected.Boat == (Object)null) && !((Object)(object)selected.Saveable == (Object)null) && !((Object)(object)selected.Port == (Object)null) && !((Object)(object)selected.Recovery == (Object)null) && !((Object)(object)selected.Body == (Object)null) && !((Object)(object)selected.Ropes == (Object)null) && !((Object)(object)selected.StarterSet == (Object)null))
			{
				Scene scene = ((Component)selected.Port).gameObject.scene;
				if (((Scene)(ref scene)).isLoaded)
				{
					scene = ((Component)selected.Saveable).gameObject.scene;
					if (((Scene)(ref scene)).isLoaded && !((Object)(object)selected.Recovery.parentPort != (Object)(object)selected.Port) && !((Object)(object)selected.StarterSet.starterBoat != (Object)(object)((Component)selected.Saveable).transform))
					{
						if (StartingBoatsField.GetValue(menu) is PurchasableBoat[] array && selected.Region < array.Length)
						{
							return (Object)(object)array[selected.Region] == (Object)(object)selected.Boat;
						}
						return false;
					}
				}
			}
			return false;
		}
	}
	internal sealed class IndividualExclusions
	{
		private readonly HashSet<string> excludedPorts = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private readonly HashSet<string> excludedBoats = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		internal bool IsPortExcluded(PortChoice port)
		{
			if (port != null)
			{
				return excludedPorts.Contains(port.IdentityName);
			}
			return false;
		}

		internal bool IsBoatExcluded(BoatChoice boat)
		{
			if (boat != null)
			{
				return excludedBoats.Contains(boat.IdentityName);
			}
			return false;
		}

		internal bool SetPortExcluded(PortChoice port, bool excluded)
		{
			if (port != null)
			{
				return Set(excludedPorts, port.IdentityName, excluded);
			}
			return false;
		}

		internal bool SetBoatExcluded(BoatChoice boat, bool excluded)
		{
			if (boat != null)
			{
				return Set(excludedBoats, boat.IdentityName, excluded);
			}
			return false;
		}

		internal IndividualExclusions Copy()
		{
			IndividualExclusions individualExclusions = new IndividualExclusions();
			individualExclusions.ReplaceWith(this);
			return individualExclusions;
		}

		internal void ReplaceWith(IndividualExclusions source)
		{
			if (source != null && source != this)
			{
				excludedPorts.Clear();
				excludedBoats.Clear();
				excludedPorts.UnionWith(source.excludedPorts);
				excludedBoats.UnionWith(source.excludedBoats);
			}
		}

		internal string SavePorts()
		{
			return Encode(excludedPorts);
		}

		internal string SaveBoats()
		{
			return Encode(excludedBoats);
		}

		internal static IndividualExclusions Load(string ports, string boats)
		{
			IndividualExclusions individualExclusions = new IndividualExclusions();
			Decode(ports, individualExclusions.excludedPorts);
			Decode(boats, individualExclusions.excludedBoats);
			return individualExclusions;
		}

		private static bool Set(HashSet<string> names, string name, bool excluded)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			if (!excluded)
			{
				return names.Remove(name);
			}
			return names.Add(name);
		}

		private static string Encode(HashSet<string> names)
		{
			return string.Join(";", names.OrderBy<string, string>((string name) => name, StringComparer.OrdinalIgnoreCase).Select(Uri.EscapeDataString));
		}

		private static void Decode(string saved, HashSet<string> names)
		{
			string[] array = (saved ?? "").Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = Uri.UnescapeDataString(array[i]);
				if (!string.IsNullOrWhiteSpace(text))
				{
					names.Add(text);
				}
			}
		}
	}
	internal static class LeopardStarterRig
	{
		[HarmonyPatch(typeof(ShipyardSailColChecker), "ParentToWalkColMast")]
		private static class ResumeClothAfterNativeReparent
		{
			private static void Postfix(ShipyardSailColChecker __instance)
			{
				RestartInterruptedCloth(__instance);
			}
		}

		[HarmonyPatch(typeof(GPButtonRopeWinch), "OnActivate")]
		private static class ReleaseOnWinchActivation
		{
			private static void Prefix(GPButtonRopeWinch __instance)
			{
				ObserveWinchInput(__instance);
			}
		}

		[HarmonyPatch(typeof(GPButtonRopeWinch), "Update")]
		private static class ReleaseOnWinchInput
		{
			private static void Prefix(GPButtonRopeWinch __instance)
			{
				if ((Object)(object)diagnosticWinch != (Object)null && Time.realtimeSinceStartup >= diagnosticExpiresAt)
				{
					ClearControlDiagnostic();
				}
				if ((__instance == pendingWinch || __instance == diagnosticWinch) && WinchInUse(__instance))
				{
					ObserveWinchInput(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(SaveLoadManager), "LoadGame")]
		private static class CancelOnLoad
		{
			private static void Prefix()
			{
				Cancel();
			}
		}

		private const int BoatIndex = 207;

		private const string BoatName = "BOAT LEOPARD (207)(Clone)";

		private const string MastPath = "boat leopard/structure_container/MAINMAST/mainmast";

		private const int SailIndex = 60;

		private const string SailName = "60 SAIL Am lateen mid";

		private static readonly MethodInfo AttachInitialSail = AccessTools.Method(typeof(Mast), "AttachInitialSail", new Type[2]
		{
			typeof(GameObject),
			typeof(float)
		}, (Type[])null);

		private static readonly MethodInfo UpdateSailUnroll = AccessTools.Method(typeof(RopeControllerSailReef), "UpdateSailUnroll", Type.EmptyTypes, (Type[])null);

		private static readonly FieldInfo VisualAnimator = AccessTools.Field(typeof(ReefEffectAnimUniversal), "anim");

		private static readonly FieldInfo VisualRefreshing = AccessTools.Field(typeof(ReefEffectAnimUniversal), "refreshing");

		private static readonly FieldInfo VisualFurled = AccessTools.Field(typeof(ReefEffectAnimUniversal), "isFurled");

		private static readonly FieldInfo VisualUnfurledMaterial = AccessTools.Field(typeof(ReefEffectAnimUniversal), "unfurledMaterial");

		private static readonly FieldInfo WinchClicked = AccessTools.Field(typeof(GoPointerButton), "isClicked");

		private static readonly FieldInfo WinchStickyClickedBy = AccessTools.Field(typeof(GoPointerButton), "stickyClickedBy");

		private static GPButtonRopeWinch pendingWinch;

		private static ShipyardSailColChecker pendingChecker;

		private static StartMenu pendingMenu;

		private static ResolvedStart pendingStart;

		private static int pendingRefreshGeneration;

		private static GPButtonRopeWinch diagnosticWinch;

		private static RopeControllerSailReef diagnosticReef;

		private static float diagnosticExpiresAt;

		private static int generation;

		internal static void Cancel()
		{
			generation++;
			pendingWinch = null;
			ClearClothRestart();
			ClearControlDiagnostic();
		}

		private static void ClearClothRestart()
		{
			pendingChecker = null;
			pendingMenu = null;
			pendingStart = null;
		}

		private static void RestartInterruptedCloth(ShipyardSailColChecker checker)
		{
			if (checker != pendingChecker || (Object)(object)pendingChecker == (Object)null)
			{
				return;
			}
			StartMenu menu = pendingMenu;
			ResolvedStart resolvedStart = pendingStart;
			int token = pendingRefreshGeneration;
			ClearClothRestart();
			try
			{
				if (resolvedStart == null || !StillSelected(menu, resolvedStart, token) || !GameState.playing || GameState.currentlyLoading || (Object)(object)pendingWinch == (Object)null)
				{
					return;
				}
				if (WinchInUse(pendingWinch))
				{
					ObserveWinchInput(pendingWinch);
					return;
				}
				RopeController rope = pendingWinch.rope;
				RopeControllerSailReef val = (RopeControllerSailReef)(object)((rope is RopeControllerSailReef) ? rope : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val.sail == (Object)null || (Object)(object)val.sail.shipRigidbody != (Object)(object)resolvedStart.Body || !HasInitialFurlLength(val.reverseReefing, ((RopeController)val).currentLength))
				{
					return;
				}
				ReefEffectAnimUniversal component = ((Component)val.sail).GetComponent<ReefEffectAnimUniversal>();
				if (!((Object)(object)component == (Object)null) && ((Behaviour)component).isActiveAndEnabled)
				{
					object? value = VisualAnimator.GetValue(component);
					Animator val2 = (Animator)((value is Animator) ? value : null);
					if (val2 != null && !((Object)(object)val2 == (Object)null) && (bool)VisualRefreshing.GetValue(component))
					{
						component.RefreshCloth();
						Plugin.Instance.Report("Leopard starter sail: resumed native cloth refresh after initial collision-checker reparenting.");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance?.Warn("Leopard native cloth refresh could not resume: " + ex.Message);
			}
		}

		private static bool WinchInUse(GPButtonRopeWinch winch)
		{
			if (!(bool)WinchClicked.GetValue(winch))
			{
				object? value = WinchStickyClickedBy.GetValue(winch);
				GoPointer val = (GoPointer)((value is GoPointer) ? value : null);
				if (val == null || !((Object)(object)val != (Object)null))
				{
					if ((Object)(object)winch.rotHandle != (Object)null)
					{
						return winch.rotHandle.IsGrabbed();
					}
					return false;
				}
			}
			return true;
		}

		private static void ClearControlDiagnostic()
		{
			diagnosticWinch = null;
			diagnosticReef = null;
			diagnosticExpiresAt = 0f;
		}

		private static void ObserveWinchInput(GPButtonRopeWinch winch)
		{
			try
			{
				RopeControllerSailReef val = ((winch == diagnosticWinch && Time.realtimeSinceStartup < diagnosticExpiresAt) ? diagnosticReef : null);
				if ((Object)(object)val != (Object)null)
				{
					ClearControlDiagnostic();
				}
				if (winch == pendingWinch)
				{
					ReleaseToPlayer();
				}
				if ((Object)(object)val != (Object)null && (Object)(object)Plugin.Instance != (Object)null)
				{
					((MonoBehaviour)Plugin.Instance).StartCoroutine(ObserveControlChange(val, generation));
				}
			}
			catch (Exception ex)
			{
				if (winch == pendingWinch)
				{
					Cancel();
				}
				ClearControlDiagnostic();
				Plugin.Instance?.Warn("Leopard first-input diagnostic unavailable: " + ex.Message);
			}
		}

		private static IEnumerator ObserveControlChange(RopeControllerSailReef reef, int token)
		{
			if (!((Object)(object)reef == (Object)null) && token == generation && !GameState.currentlyLoading)
			{
				float deadline = Time.realtimeSinceStartup + 3f;
				float original = ((RopeController)reef).currentLength;
				while (token == generation && (Object)(object)reef != (Object)null && ((RopeController)reef).currentLength == original && Time.realtimeSinceStartup < deadline)
				{
					yield return null;
				}
				yield return (object)new WaitForEndOfFrame();
				yield return (object)new WaitForEndOfFrame();
				if (token == generation && !GameState.currentlyLoading && (Object)(object)reef != (Object)null)
				{
					ReportVisualState(reef, "first player reef input (read-only)");
				}
			}
		}

		private static void ReleaseToPlayer()
		{
			Plugin.Instance?.Report("Leopard starter furl initialization released to player winch input.");
			Cancel();
		}

		internal static void Arm(StartMenu menu, ResolvedStart selected)
		{
			if (selected.Saveable.sceneIndex != 207 || ((Object)selected.Saveable).name != "BOAT LEOPARD (207)(Clone)")
			{
				return;
			}
			Cancel();
			int token = generation;
			try
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(InstallAfterStart(menu, selected, token));
			}
			catch (Exception ex)
			{
				Plugin.Instance.Warn("Leopard starter sail could not be scheduled: " + ex.Message);
			}
		}

		private static bool StillSelected(StartMenu menu, ResolvedStart selected, int token)
		{
			if (token == generation && (Object)(object)Plugin.Instance != (Object)null)
			{
				return FixedStart.IsSelectionStillActive(menu, selected);
			}
			return false;
		}

		private static IEnumerator InstallAfterStart(StartMenu menu, ResolvedStart selected, int token)
		{
			while (true)
			{
				if (!StillSelected(menu, selected, token))
				{
					yield break;
				}
				if (GameState.playing && !GameState.currentlyLoading && selected.Boat.isPurchased())
				{
					break;
				}
				yield return null;
			}
			int frame = 0;
			while (frame < 4)
			{
				yield return (object)new WaitForFixedUpdate();
				int num = frame + 1;
				frame = num;
			}
			yield return (object)new WaitForEndOfFrame();
			yield return (object)new WaitForEndOfFrame();
			if (StillSelected(menu, selected, token) && GameState.playing && !GameState.currentlyLoading && selected.Boat.isPurchased())
			{
				RopeControllerSailReef val = null;
				try
				{
					val = Install(selected);
				}
				catch (Exception ex)
				{
					Plugin.Instance.Warn("Leopard starter sail needs an in-game check; attachment was not retried: " + ex);
				}
				if ((Object)(object)val != (Object)null)
				{
					pendingChecker = ((Component)val.sail).GetComponent<SailConnections>().colChecker;
					pendingMenu = menu;
					pendingStart = selected;
					pendingRefreshGeneration = token;
					yield return FinalizeFurl(menu, selected, token, val);
				}
			}
		}

		private static IEnumerator FinalizeFurl(StartMenu menu, ResolvedStart selected, int token, RopeControllerSailReef reef)
		{
			float deadline = Time.realtimeSinceStartup + 3f;
			int frames = 0;
			string lastState = "native visual Start not observed";
			try
			{
				while (Time.realtimeSinceStartup < deadline)
				{
					if (!StillSelected(menu, selected, token) || !GameState.playing || GameState.currentlyLoading || (Object)(object)reef == (Object)null || (Object)(object)reef.sail == (Object)null || (Object)(object)pendingWinch == (Object)null || (Object)(object)pendingWinch.rope != (Object)(object)reef)
					{
						yield break;
					}
					bool flag = false;
					bool flag2 = false;
					try
					{
						ReefEffectAnimUniversal component;
						int num;
						if (WinchInUse(pendingWinch))
						{
							ObserveWinchInput(pendingWinch);
							flag = true;
						}
						else
						{
							if (HasInitialFurlLength(reef.reverseReefing, ((RopeController)reef).currentLength))
							{
								component = ((Component)reef.sail).GetComponent<ReefEffectAnimUniversal>();
								if ((Object)(object)component != (Object)null)
								{
									object? value = VisualAnimator.GetValue(component);
									Animator val = (Animator)((value is Animator) ? value : null);
									if (val != null)
									{
										num = (((Object)(object)val != (Object)null) ? 1 : 0);
										goto IL_017e;
									}
								}
								num = 0;
								goto IL_017e;
							}
							Plugin.Instance.Warn($"Leopard starter furl initialization released: reef length changed to {((RopeController)reef).currentLength:F3}, unroll {reef.sail.currentUnroll:F3}.");
							flag = true;
						}
						goto end_IL_00c6;
						IL_017e:
						bool flag3 = (byte)num != 0;
						bool flag4 = (Object)(object)component == (Object)null || (bool)VisualRefreshing.GetValue(component);
						lastState = $"reef {((RopeController)reef).currentLength:F3}, unroll {reef.sail.currentUnroll:F3}, animator ready {flag3}, refreshing {flag4}, native visual update {(Object)(object)component != (Object)null && component.debugToggleCloth}";
						if (frames >= 2 && flag3 && !flag4 && component.debugToggleCloth)
						{
							ReportVisualState(reef, "native initialization (read-only)");
							Plugin.Instance.Report("Leopard native sail initialization observed; visible furl and animation remain unconfirmed. First reef input within 60 seconds will record one diagnostic.");
							flag2 = true;
						}
						end_IL_00c6:;
					}
					catch (Exception ex)
					{
						Plugin.Instance.Warn("Leopard starter furl could not be confirmed: " + ex.Message);
						flag = true;
					}
					if (flag || flag2)
					{
						yield break;
					}
					int num2 = frames + 1;
					frames = num2;
					yield return null;
				}
				ReportVisualState(reef, "native initialization timeout (read-only)");
				Plugin.Instance.Warn("Leopard starter sail installed, but native visual readiness was not observed within the bounded initialization window: " + lastState + ".");
			}
			finally
			{
				if (token == generation)
				{
					pendingWinch = null;
					ClearClothRestart();
				}
			}
		}

		private static bool HasInitialFurlLength(bool reverse, float length)
		{
			return length == (reverse ? 1f : 0f);
		}

		private static void ReportVisualState(RopeControllerSailReef reef, string phase)
		{
			//IL_00c3: 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_0117: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)reef == (Object)null) && !((Object)(object)reef.sail == (Object)null))
				{
					Sail sail = reef.sail;
					ReefEffectAnimUniversal component = ((Component)sail).GetComponent<ReefEffectAnimUniversal>();
					Animator val = (Animator)(((Object)(object)component == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
					SkinnedMeshRenderer val2 = (((Object)(object)sail.cloth == (Object)null) ? null : ((Component)sail.cloth).GetComponent<SkinnedMeshRenderer>());
					Material material = (Material)(((Object)(object)component == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
					object obj2;
					if (!((Object)(object)val == (Object)null))
					{
						object[] obj = new object[5]
						{
							((Behaviour)val).enabled,
							val.isInitialized,
							val.speed,
							val.cullingMode,
							null
						};
						RuntimeAnimatorController runtimeAnimatorController = val.runtimeAnimatorController;
						obj[4] = ((runtimeAnimatorController != null) ? ((Object)runtimeAnimatorController).name : null);
						obj2 = string.Format("enabled {0}, initialized {1}, speed {2:F3}, culling {3}, controller {4}", obj);
					}
					else
					{
						obj2 = "missing";
					}
					string text = (string)obj2;
					if ((Object)(object)val != (Object)null && val.isInitialized && (Object)(object)component != (Object)null)
					{
						AnimatorStateInfo currentAnimatorStateInfo = val.GetCurrentAnimatorStateInfo(component.layer);
						text += $", state {((AnimatorStateInfo)(ref currentAnimatorStateInfo)).shortNameHash}, expected {Animator.StringToHash(component.clipName)}, time {((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime:F3}";
					}
					string text2 = (((Object)(object)val2 == (Object)null) ? "<missing cloth>" : string.Join("; ", ((IEnumerable<Transform>)(((object)val2.bones) ?? ((object)new Transform[0]))).Where((Transform bone) => (Object)(object)bone != (Object)null).Take(4).Select(delegate(Transform bone)
					{
						//IL_001a: Unknown result type (might be due to invalid IL or missing references)
						//IL_001f: Unknown result type (might be due to invalid IL or missing references)
						//IL_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_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)
						string[] obj3 = new string[7]
						{
							((Object)bone).name,
							": position ",
							null,
							null,
							null,
							null,
							null
						};
						Vector3 val3 = bone.localPosition;
						obj3[2] = ((Vector3)(ref val3)).ToString("F3");
						obj3[3] = ", rotation ";
						Quaternion localRotation = bone.localRotation;
						obj3[4] = ((Quaternion)(ref localRotation)).ToString("F3");
						obj3[5] = ", scale ";
						val3 = bone.localScale;
						obj3[6] = ((Vector3)(ref val3)).ToString("F3");
						return string.Concat(obj3);
					})));
					Plugin.Instance.Report($"Leopard sail diagnostic [{phase}]: reef {((RopeController)reef).currentLength:F3}, unroll {sail.currentUnroll:F3}; animator {text}; " + string.Format("r