Decompiled source of New Beginnings v1.0.1
BepInEx/plugins/NewBeginnings/NewBeginnings.dll
Decompiled 2 hours ago
The result has been truncated due to the large size, download it to view full contents!
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