Decompiled source of SwappableStaysail v1.2.1
BepInEx/plugins/SwappableStaysail/SwappableStaysail.dll
Decompiled a week 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.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.SceneManagement; using cakeslice; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("SwappableStaysail")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.1.0")] [assembly: AssemblyInformationalVersion("1.2.1")] [assembly: AssemblyProduct("SwappableStaysail")] [assembly: AssemblyTitle("SwappableStaysail")] [assembly: AssemblyVersion("1.2.1.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 SwappableStaysail { [BepInPlugin("DogEggz", "Swappable Staysail", "1.2.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class SwappableStaysailPlugin : BaseUnityPlugin { public const string PluginGuid = "DogEggz"; public const string PluginName = "Swappable Staysail"; public const string PluginVersion = "1.2.1"; public const string ShipyardExpansionGuid = "com.nandbrew.shipyardexpansion"; internal const string SaveDataKey = "DogEggz"; private Harmony harmony; internal static SwappableStaysailPlugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; harmony = new Harmony("DogEggz"); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Swappable Staysail 1.2.1 loaded. Sail package prefab indexes: legacy=" + $"{390}, standard=" + $"{600}, small=" + $"{601}.")); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } SailmakerSession.Dispose(); StayInstallTargeting.Dispose(); FurledStaysailButton.DisposeAll(); SailpackFactory.Dispose(); SailpackPersistence.Dispose(); Instance = null; Log = null; } } internal static class StaysailInteractionVisuals { private static readonly FieldInfo PointedAtButtonField = AccessTools.Field(typeof(GoPointer), "pointedAtButton"); internal static void ResetAfterInteraction() { Reset(); } internal static void ResetForShipyard() { Reset(); } private static void Reset() { StayInstallTargeting.Deactivate(); FurledStaysailButton.ResetAllInteractionVisuals(); ClearPointerTargets(); } private static void ClearPointerTargets() { if (PointedAtButtonField == null) { return; } GoPointer[] array = Object.FindObjectsOfType<GoPointer>(); foreach (GoPointer obj in array) { object? value = PointedAtButtonField.GetValue(obj); GoPointerButton val = (GoPointerButton)((value is GoPointerButton) ? value : null); if (!((Object)(object)val == (Object)null) && (val is StayInstallTargetButton || val is FurledStaysailButton)) { val.ForceUnlook(); val.Unclick(); PointedAtButtonField.SetValue(obj, null); } } } } [HarmonyPatch(typeof(GoPointer), "DoRaycast")] internal static class StayInstallRaycastPatch { [HarmonyPrefix] private static void Prefix(GoPointer __instance) { StayInstallTargeting.PrepareRaycast(__instance); } } [HarmonyPatch(typeof(GoPointer), "LateUpdate")] internal static class StaysailInstallActivatePatch { [HarmonyPrefix] private static void Prefix(GoPointer __instance, GoPointerButton ___pointedAtButton) { if (StaysailInput.ActivateDown(__instance) && ___pointedAtButton is StayInstallTargetButton { IsAvailable: not false } stayInstallTargetButton) { stayInstallTargetButton.TryInstall(__instance.GetHeldItem()); } } } [HarmonyPatch(typeof(Mast), "Start")] internal static class MastStartPatch { [HarmonyPostfix] private static void Postfix(Mast __instance) { StaysailTargets.EnsureRuntimeButtons(__instance); } } [HarmonyPatch(typeof(Mast), "AttachSailToMast")] internal static class MastAttachPatch { [HarmonyPostfix] private static void Postfix(Mast __instance, GameObject sailObject) { StaysailTargets.EnsureRuntimeButtons(__instance); StaysailTargets.EnsureRemovalButton(__instance, sailObject); } } internal static class StaysailInstaller { internal static bool TryInstall(SailpackData data, Mast mast, out string error) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Invalid comparison between Unknown and I4 //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) error = null; SailpackRecord sailpackRecord = data?.Record; GameObject val = data?.GetSailPrefab(); Sail val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Sail>() : null); if (!StaysailTargets.IsEligible(mast)) { error = "That stay cannot accept swappable staysails."; return false; } if (sailpackRecord == null || (Object)(object)val2 == (Object)null || (int)val2.category != 5) { error = "The sail model in this sail package is unavailable."; return false; } if (mast.sails == null || mast.sails.Count >= mast.maxSails) { error = "That stay has no free sail slot."; return false; } GameObject val3 = null; bool flag = false; try { val3 = Object.Instantiate<GameObject>(val, ((Component)mast).transform.position, ((Component)mast).transform.rotation); Sail component = val3.GetComponent<Sail>(); ((Behaviour)component).enabled = false; Rigidbody component2 = val3.GetComponent<Rigidbody>(); if ((Object)(object)component2 != (Object)null) { component2.isKinematic = true; } val3.transform.SetParent(((Component)mast).transform, true); component.ChangeInstallHeight(sailpackRecord.installHeight); component.LoadScale(sailpackRecord.scaleY, sailpackRecord.scaleZ); component.ChangeSailColor(sailpackRecord.sailColor); SailConnections component3 = val3.GetComponent<SailConnections>(); if ((Object)(object)component3 == (Object)null || (Object)(object)component3.colChecker == (Object)null) { throw new InvalidOperationException("Sail connection data is missing."); } if (!HasControllerCapacity(mast, mast.sails.Count, component3)) { error = "That stay has no free winch connection."; Object.Destroy((Object)(object)val3); return false; } component3.colChecker.colAngleMin = sailpackRecord.minAngle; component3.colChecker.colAngleMax = sailpackRecord.maxAngle; component.UpdateInstallPosition(); float num = component.GetCurrentInstallHeight() - component.GetScaledHeight(); if (component.GetScaledHeight() > mast.mastHeight || num < -0.1f) { error = "The packed sail does not fit this stay."; Object.Destroy((Object)(object)val3); return false; } foreach (GameObject sail in mast.sails) { Sail val4 = (((Object)(object)sail != (Object)null) ? sail.GetComponent<Sail>() : null); if (!((Object)(object)val4 == (Object)null)) { float num2 = val4.GetCurrentInstallHeight() - val4.GetScaledHeight(); if (Mathf.Max(num, num2) <= Mathf.Min(component.GetCurrentInstallHeight(), val4.GetCurrentInstallHeight())) { error = "The packed sail overlaps another sail."; Object.Destroy((Object)(object)val3); return false; } } } mast.AttachSailToMast(val3); if (!component.IsInstalled() || mast.sails == null || !mast.sails.Contains(val3)) { throw new InvalidOperationException("The stay did not retain the installed sail."); } flag = true; try { StaysailTargets.EnsureRemovalButton(mast, val3); } catch (Exception arg) { ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogWarning((object)("Staysail installed, but its removal target could not be " + $"created immediately: {arg}")); } } ConsumePackage(data); try { StaysailInteractionVisuals.ResetAfterInteraction(); } catch (Exception ex) { ManualLogSource log2 = SwappableStaysailPlugin.Log; if (log2 != null) { log2.LogWarning((object)("Installed staysail interaction cleanup failed: " + ex)); } } ManualLogSource log3 = SwappableStaysailPlugin.Log; if (log3 != null) { log3.LogInfo((object)("Installed " + sailpackRecord.GetDisplayName() + " on " + $"boat {sailpackRecord.targetBoatSceneIndex}, stay " + $"{sailpackRecord.targetMastOrderIndex}.")); } return true; } catch (Exception arg2) { if (!flag && (Object)(object)val3 != (Object)null) { Sail component4 = val3.GetComponent<Sail>(); if (mast?.sails != null && mast.sails.Contains(val3) && (Object)(object)component4 != (Object)null) { StaysailDetacher.TryDetach(mast, component4, out var error2); if (!string.IsNullOrEmpty(error2)) { ManualLogSource log4 = SwappableStaysailPlugin.Log; if (log4 != null) { log4.LogWarning((object)("Partial install rollback: " + error2)); } } } else { Object.Destroy((Object)(object)val3); } } error = "Could not install the packed sail."; ManualLogSource log5 = SwappableStaysailPlugin.Log; if (log5 != null) { log5.LogError((object)$"Sail package installation failed: {arg2}"); } return false; } } private static void ConsumePackage(SailpackData data) { if ((Object)(object)data == (Object)null) { return; } try { ConsumePackageCore(data); } catch (Exception arg) { ShipItem component = ((Component)data).GetComponent<ShipItem>(); GoPointer val = (((Object)(object)component != (Object)null) ? ((PickupableItem)component).held : null); try { if (val != null) { val.DropItem(); } } catch (Exception ex) { if ((Object)(object)component != (Object)null) { ((PickupableItem)component).held = null; } ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogWarning((object)("Fallback pointer cleanup failed after install: " + ex)); } } SailpackFactory.DiscardStaged(data, unregisterFromSave: true); ManualLogSource log2 = SwappableStaysailPlugin.Log; if (log2 != null) { log2.LogWarning((object)("Used fallback sail-package cleanup after a committed " + $"install: {arg}")); } } } private static void ConsumePackageCore(SailpackData data) { ShipItem component = ((Component)data).GetComponent<ShipItem>(); SaveablePrefab component2 = ((Component)data).GetComponent<SaveablePrefab>(); GoPointer val = (((Object)(object)component != (Object)null) ? ((PickupableItem)component).held : null); if ((Object)(object)component2 != (Object)null && component2.instanceId > 0) { SailpackPersistence.Remove(component2.instanceId); } if ((Object)(object)val != (Object)null) { try { ((PickupableItem)component).OnDrop(); } catch (Exception ex) { ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogWarning((object)("Sail package drop callback failed during install: " + ex)); } } try { val.DropItem(); } catch (Exception ex2) { ((PickupableItem)component).held = null; ManualLogSource log2 = SwappableStaysailPlugin.Log; if (log2 != null) { log2.LogWarning((object)("Sail package pointer release failed during install: " + ex2)); } } } ((Component)data).gameObject.SetActive(false); try { if ((Object)(object)component != (Object)null) { component.DestroyItem(); return; } if (component2 != null) { component2.Unregister(); } Object.Destroy((Object)(object)((Component)data).gameObject); } catch (Exception ex3) { try { if (component2 != null) { component2.Unregister(); } } catch (Exception ex4) { ManualLogSource log3 = SwappableStaysailPlugin.Log; if (log3 != null) { log3.LogWarning((object)("Sail package save cleanup failed after install: " + ex4)); } } Object.Destroy((Object)(object)((Component)data).gameObject); ManualLogSource log4 = SwappableStaysailPlugin.Log; if (log4 != null) { log4.LogWarning((object)("Sail package used fallback destruction after install: " + ex3)); } } } private static bool HasControllerCapacity(Mast mast, int index, SailConnections connections) { if ((Object)(object)connections.reefController != (Object)null && (mast.reefWinch == null || index >= mast.reefWinch.Length)) { return false; } if ((Object)(object)connections.angleControllerMid != (Object)null && (mast.midAngleWinch == null || index >= mast.midAngleWinch.Length)) { return false; } if (((Object)(object)connections.angleControllerLeft != (Object)null || (Object)(object)connections.angleControllerRight != (Object)null) && (mast.leftAngleWinch == null || index >= mast.leftAngleWinch.Length || mast.rightAngleWinch == null || index >= mast.rightAngleWinch.Length)) { return false; } if ((Object)(object)connections.mastReefAttachment != (Object)null && (mast.mastReefAtt == null || index >= mast.mastReefAtt.Length)) { return false; } return true; } } internal sealed class StayInstallTargetButton : GoPointerButton { private Mast target; private SailpackData data; private Collider interactionCollider; private string interactionLabel; internal bool IsAvailable { get { if (!base.unclickable && (Object)(object)data != (Object)null && data.HasRecord && (Object)(object)interactionCollider != (Object)null) { return interactionCollider.enabled; } return false; } } internal void Initialize(Mast newTarget, Collider collider) { target = newTarget; interactionCollider = collider; } internal void Configure(Mast newTarget, SailpackData newData, string activateLabel) { target = newTarget; data = newData; interactionLabel = activateLabel; base.lookText = (((Object)(object)data != (Object)null && data.HasRecord) ? (interactionLabel + ": install " + data.Record.GetDisplayName()) : (interactionLabel + ": install staysail")); } internal void SetAvailable(bool available) { base.unclickable = !available; if (available && !((Component)this).gameObject.activeSelf) { ((Component)this).gameObject.SetActive(true); } if ((Object)(object)interactionCollider != (Object)null) { interactionCollider.enabled = available; } if (!available && ((Component)this).gameObject.activeSelf) { ((Component)this).gameObject.SetActive(false); } } internal void ResetInteractionVisuals() { SetAvailable(available: false); ((GoPointerButton)this).ForceUnlook(); ((GoPointerButton)this).Unclick(); base.overrideEnableOutline = false; Outline[] components = ((Component)this).GetComponents<Outline>(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } } internal void DisposeInteractionVolume() { if ((Object)(object)interactionCollider != (Object)null) { Object.Destroy((Object)(object)((Component)interactionCollider).gameObject); interactionCollider = null; } } internal void TryInstall(PickupableItem heldItem) { SailpackData sailpackData = (((Object)(object)heldItem != (Object)null) ? ((Component)heldItem).GetComponent<SailpackData>() : null); if (!((Object)(object)sailpackData == (Object)null) && !((Object)(object)sailpackData != (Object)(object)data) && !((Object)(object)target == (Object)null) && !StaysailInstaller.TryInstall(sailpackData, target, out var error)) { NotificationUi instance = NotificationUi.instance; if (instance != null) { instance.ShowNotification(error); } } } public override bool OnItemClick(PickupableItem heldItem) { return false; } public override void OnAltActivate(GoPointer activatingPointer) { if ((Object)(object)activatingPointer != (Object)null && IsAvailable) { TryInstall(activatingPointer.GetHeldItem()); } } } internal sealed class StayInstallTargetProxy : MonoBehaviour { } internal static class StayInstallTargeting { private static readonly Dictionary<Mast, List<StayInstallTargetButton>> Buttons = new Dictionary<Mast, List<StayInstallTargetButton>>(); private static SailpackData cachedData; private static Mast cachedTarget; private static List<StayInstallTargetButton> availableButtons; private static GoPointer activePointer; private static SailpackData activeData; private static Mast activeTarget; private static string activeLabel; internal static void PrepareRaycast(GoPointer pointer) { if ((Object)(object)pointer == (Object)null || GameState.sleeping || Object.op_Implicit((Object)(object)GameState.inBed) || BoatCamera.on || (Object)(object)GameState.currentShipyard != (Object)null) { Deactivate(pointer); return; } PickupableItem heldItem = pointer.GetHeldItem(); SailpackData sailpackData = (((Object)(object)heldItem != (Object)null) ? ((Component)heldItem).GetComponent<SailpackData>() : null); if ((Object)(object)sailpackData == (Object)null) { Deactivate(pointer); return; } Mast val = ResolveTarget(sailpackData); if ((Object)(object)val == (Object)null) { Deactivate(pointer); return; } List<StayInstallTargetButton> orCreateButtons = GetOrCreateButtons(val); if (orCreateButtons == null || orCreateButtons.Count == 0) { Deactivate(pointer); return; } string text = StaysailInput.ActivateLabel(pointer); if (!((Object)(object)activePointer != (Object)(object)pointer) && availableButtons == orCreateButtons && !((Object)(object)activeData != (Object)(object)sailpackData) && !((Object)(object)activeTarget != (Object)(object)val) && !(activeLabel != text)) { return; } if (availableButtons != orCreateButtons || (Object)(object)activePointer != (Object)(object)pointer) { DisableAvailableButtons(); availableButtons = orCreateButtons; } activePointer = pointer; activeData = sailpackData; activeTarget = val; activeLabel = text; foreach (StayInstallTargetButton availableButton in availableButtons) { if ((Object)(object)availableButton != (Object)null) { availableButton.Configure(val, sailpackData, text); availableButton.SetAvailable(available: true); } } } private static Mast ResolveTarget(SailpackData data) { if ((Object)(object)data == (Object)null || data.Record == null) { cachedData = null; cachedTarget = null; return null; } if ((Object)(object)cachedData != (Object)(object)data || (Object)(object)cachedTarget == (Object)null || !((Component)cachedTarget).gameObject.activeInHierarchy) { bool num = (Object)(object)cachedData != (Object)(object)data; cachedData = data; cachedTarget = StaysailTargets.Resolve(data); if (num && (Object)(object)cachedTarget == (Object)null) { ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogWarning((object)("Could not resolve target stay for " + data.Record.GetDisplayName() + " (boat " + $"{data.Record.targetBoatSceneIndex}, mast " + $"{data.Record.targetMastOrderIndex}).")); } } } return cachedTarget; } internal static List<StayInstallTargetButton> GetOrCreateButtons(Mast mast) { PruneButtons(); if ((Object)(object)mast == (Object)null) { return null; } if (Buttons.TryGetValue(mast, out var value) && value != null && value.Count > 0) { return value; } List<Collider> list = CreateInteractionColliders(mast); if (list.Count == 0) { return null; } List<StayInstallTargetButton> list2 = new List<StayInstallTargetButton>(list.Count); foreach (Collider item in list) { if (!((Object)(object)item == (Object)null)) { ((Renderer)((Component)item).gameObject.AddComponent<MeshRenderer>()).enabled = false; StayInstallTargetButton stayInstallTargetButton = ((Component)item).gameObject.AddComponent<StayInstallTargetButton>(); stayInstallTargetButton.Initialize(mast, item); stayInstallTargetButton.Configure(mast, null, StaysailInput.DefaultActivateLabel); stayInstallTargetButton.SetAvailable(available: false); list2.Add(stayInstallTargetButton); } } Buttons[mast] = list2; return list2; } private static List<Collider> CreateInteractionColliders(Mast mast) { List<Collider> list = new List<Collider>(); HashSet<GameObject> hashSet = new HashSet<GameObject>(); Collider[] componentsInChildren = ((Component)mast).GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if (IsInteractionSource((Component)(object)val)) { Collider val2 = CopyCollider(val, mast); if ((Object)(object)val2 != (Object)null) { list.Add(val2); hashSet.Add(((Component)val).gameObject); } } } Renderer[] componentsInChildren2 = ((Component)mast).GetComponentsInChildren<Renderer>(true); foreach (Renderer val3 in componentsInChildren2) { if (IsInteractionSource((Component)(object)val3) && !hashSet.Contains(((Component)val3).gameObject)) { Collider val4 = CreateRendererCollider(val3, mast); if ((Object)(object)val4 != (Object)null) { list.Add(val4); } } } return list; } private static bool IsInteractionSource(Component component) { if ((Object)(object)component != (Object)null && (Object)(object)component.GetComponentInParent<Sail>() == (Object)null && (Object)(object)component.GetComponentInParent<StayInstallTargetProxy>() == (Object)null) { return (Object)(object)component.GetComponentInParent<PickupableItem>() == (Object)null; } return false; } private static Collider CopyCollider(Collider source, Mast mast) { //IL_0020: 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_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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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_0127: 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_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) GameObject val = CreateVolume(((Component)source).transform); Collider val2 = null; CapsuleCollider val3 = (CapsuleCollider)(object)((source is CapsuleCollider) ? source : null); if (val3 != null) { CapsuleCollider obj = val.AddComponent<CapsuleCollider>(); obj.center = val3.center; obj.direction = val3.direction; obj.height = val3.height + 0.16f; obj.radius = val3.radius + 0.08f; val2 = (Collider)(object)obj; } else { BoxCollider val4 = (BoxCollider)(object)((source is BoxCollider) ? source : null); if (val4 != null) { BoxCollider obj2 = val.AddComponent<BoxCollider>(); obj2.center = val4.center; obj2.size = val4.size + Vector3.one * 0.16f; val2 = (Collider)(object)obj2; } else { SphereCollider val5 = (SphereCollider)(object)((source is SphereCollider) ? source : null); if (val5 != null) { SphereCollider obj3 = val.AddComponent<SphereCollider>(); obj3.center = val5.center; obj3.radius = val5.radius + 0.08f; val2 = (Collider)(object)obj3; } else { MeshCollider val6 = (MeshCollider)(object)((source is MeshCollider) ? source : null); if (val6 == null || !((Object)(object)val6.sharedMesh != (Object)null)) { Object.Destroy((Object)(object)val); return CreateWorldBoundsCollider(source.bounds, mast); } BoxCollider obj4 = val.AddComponent<BoxCollider>(); Bounds bounds = val6.sharedMesh.bounds; obj4.center = ((Bounds)(ref bounds)).center; bounds = val6.sharedMesh.bounds; obj4.size = ((Bounds)(ref bounds)).size + Vector3.one * 0.16f; val2 = (Collider)(object)obj4; } } } PrepareInteractionCollider(val2); return val2; } private static Collider CreateRendererCollider(Renderer source, Mast mast) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) MeshFilter component = ((Component)source).GetComponent<MeshFilter>(); Bounds val; if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) { val = component.sharedMesh.bounds; } else { SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((source is SkinnedMeshRenderer) ? source : null); if (val2 == null) { return CreateWorldBoundsCollider(source.bounds, mast); } val = val2.localBounds; } BoxCollider obj = CreateVolume(((Component)source).transform).AddComponent<BoxCollider>(); obj.center = ((Bounds)(ref val)).center; obj.size = ((Bounds)(ref val)).size + Vector3.one * 0.16f; PrepareInteractionCollider((Collider)(object)obj); return (Collider)(object)obj; } private static Collider CreateWorldBoundsCollider(Bounds bounds, Mast mast) { //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_002b: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_00a8: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) Vector3 size = ((Bounds)(ref bounds)).size; if (((Vector3)(ref size)).sqrMagnitude <= 0.0001f) { return null; } GameObject obj = CreateVolume(((Component)mast).transform); obj.transform.position = ((Bounds)(ref bounds)).center; obj.transform.rotation = Quaternion.identity; Vector3 lossyScale = obj.transform.lossyScale; BoxCollider obj2 = obj.AddComponent<BoxCollider>(); obj2.center = Vector3.zero; obj2.size = new Vector3(((Bounds)(ref bounds)).size.x / Mathf.Max(Mathf.Abs(lossyScale.x), 0.0001f), ((Bounds)(ref bounds)).size.y / Mathf.Max(Mathf.Abs(lossyScale.y), 0.0001f), ((Bounds)(ref bounds)).size.z / Mathf.Max(Mathf.Abs(lossyScale.z), 0.0001f)) + Vector3.one * 0.16f; PrepareInteractionCollider((Collider)(object)obj2); return (Collider)(object)obj2; } private static GameObject CreateVolume(Transform sourceTransform) { //IL_0005: 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_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown GameObject val = new GameObject("Swappable Staysail install target volume") { layer = 0 }; val.transform.SetParent(sourceTransform, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; val.AddComponent<StayInstallTargetProxy>(); return val; } private static void PrepareInteractionCollider(Collider collider) { collider.isTrigger = true; collider.enabled = false; } internal static void Deactivate() { DisableAvailableButtons(); cachedData = null; cachedTarget = null; activePointer = null; activeData = null; activeTarget = null; activeLabel = null; } private static void Deactivate(GoPointer pointer) { if ((Object)(object)pointer == (Object)null || (Object)(object)pointer == (Object)(object)activePointer) { Deactivate(); } } private static void DisableAvailableButtons() { if (availableButtons == null) { return; } foreach (StayInstallTargetButton availableButton in availableButtons) { availableButton?.ResetInteractionVisuals(); } availableButtons = null; } private static void PruneButtons() { List<Mast> list = new List<Mast>(); foreach (KeyValuePair<Mast, List<StayInstallTargetButton>> button in Buttons) { if ((Object)(object)button.Key == (Object)null || button.Value == null) { list.Add(button.Key); continue; } button.Value.RemoveAll((StayInstallTargetButton button) => (Object)(object)button == (Object)null); if (button.Value.Count == 0) { list.Add(button.Key); } } foreach (Mast item in list) { Buttons.Remove(item); } } internal static void Dispose() { Deactivate(); foreach (List<StayInstallTargetButton> value in Buttons.Values) { if (value == null) { continue; } foreach (StayInstallTargetButton item in value) { item?.DisposeInteractionVolume(); } } Buttons.Clear(); } } internal static class StaysailInput { internal static string DefaultActivateLabel => ((object)GameInput.GetKeyCode((InputName)9, false, false)/*cast due to .constrained prefix*/).ToString(); internal static bool ActivateDown(GoPointer pointer) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0017: Invalid comparison between Unknown and I4 if ((Object)(object)pointer == (Object)null) { return false; } PointerType type = pointer.type; if ((int)type != 0) { if ((int)type == 1) { return OVRInput.GetDown((Button)1, (Controller)int.MinValue); } if (!GameState.inCursorMenu) { return GameInput.GetKeyDown((InputName)9); } return false; } return OVRInput.GetDown((Button)4, (Controller)int.MinValue); } internal static string ActivateLabel(GoPointer pointer) { //IL_0004: 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_001b: Invalid comparison between Unknown and I4 if (pointer != null && (int)pointer.type == 0) { return "X"; } if (pointer != null && (int)pointer.type == 1) { return "A"; } return DefaultActivateLabel; } } internal static class StaysailDetacher { internal static bool TryDetach(Mast mast, Sail sail, out string error) { error = null; if ((Object)(object)mast == (Object)null || (Object)(object)sail == (Object)null || mast.sails == null || !mast.sails.Contains(((Component)sail).gameObject)) { error = "That staysail is no longer attached to this stay."; return false; } GameObject gameObject = ((Component)sail).gameObject; HashSet<GameObject> hashSet = CollectConnectionObjects(gameObject.GetComponent<SailConnections>()); gameObject.SetActive(false); Exception ex = null; try { mast.DetachSailFromMast(gameObject); } catch (Exception ex2) { ex = ex2; } mast.sails.Remove(gameObject); foreach (GameObject item in hashSet) { if ((Object)(object)item != (Object)null && (Object)(object)item != (Object)(object)gameObject) { Object.Destroy((Object)(object)item); } } Object.Destroy((Object)(object)gameObject); try { mast.UpdateSailOrder(); mast.UpdateControllerAttachments(); } catch (Exception ex3) { ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogWarning((object)("Staysail was detached, but rig refresh failed: " + ex3)); } } if (ex != null) { ManualLogSource log2 = SwappableStaysailPlugin.Log; if (log2 != null) { log2.LogWarning((object)("Vanilla staysail detachment stopped early; completed " + $"cleanup with the safe fallback: {ex}")); } } return !mast.sails.Contains(gameObject); } private static HashSet<GameObject> CollectConnectionObjects(SailConnections connections) { HashSet<GameObject> hashSet = new HashSet<GameObject>(); if ((Object)(object)connections == (Object)null) { return hashSet; } Add(hashSet, (Component)(object)connections.colChecker); Add(hashSet, (Component)(object)connections.reefController); Add(hashSet, (Component)(object)connections.angleControllerMid); Add(hashSet, (Component)(object)connections.angleControllerLeft); Add(hashSet, (Component)(object)connections.angleControllerRight); Add(hashSet, (Component)(object)connections.midRopeAttachment); Add(hashSet, (Component)(object)connections.mastReefAttachment); Add(hashSet, (Component)(object)connections.mastReefAttExtension); return hashSet; } private static void Add(HashSet<GameObject> objects, Component component) { if ((Object)(object)component != (Object)null) { objects.Add(component.gameObject); } } } internal sealed class FurledStaysailButton : GoPointerButton { private static readonly HashSet<FurledStaysailButton> Instances = new HashSet<FurledStaysailButton>(); private Mast mast; private Sail sail; private Collider targetCollider; private bool removalInProgress; internal void Initialize(Mast newMast, Sail newSail) { Instances.Add(this); mast = newMast; sail = newSail; if ((Object)(object)targetCollider == (Object)null) { FurledStaysailHitbox component = ((Component)this).GetComponent<FurledStaysailHitbox>(); targetCollider = (((Object)(object)component != (Object)null) ? component.Collider : null); } } internal void Initialize(Mast newMast, Sail newSail, Collider newTargetCollider) { targetCollider = newTargetCollider; Initialize(newMast, newSail); } public override void ExtraLateUpdate() { bool flag = !removalInProgress && CanRemove(); if ((Object)(object)targetCollider != (Object)null) { targetCollider.enabled = flag; } base.lookText = (flag ? (StaysailInput.ActivateLabel(base.pointedAtBy) + ": remove staysail to sail package") : ""); } internal static void ResetAllInteractionVisuals() { Instances.RemoveWhere((FurledStaysailButton button) => (Object)(object)button == (Object)null); foreach (FurledStaysailButton instance in Instances) { instance.ResetInteractionVisuals(); } } internal static void DisposeAll() { ResetAllInteractionVisuals(); Instances.Clear(); } internal void ResetInteractionVisuals() { ((GoPointerButton)this).ForceUnlook(); ((GoPointerButton)this).Unclick(); base.overrideEnableOutline = false; if ((Object)(object)targetCollider != (Object)null) { targetCollider.enabled = false; } Outline[] components = ((Component)this).GetComponents<Outline>(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } } public override void OnAltActivate(GoPointer activatingPointer) { //IL_0066: 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_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_0079: 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) if (removalInProgress || !CanRemove() || (Object)(object)activatingPointer == (Object)null || (Object)(object)activatingPointer.GetHeldItem() != (Object)null) { return; } removalInProgress = true; if ((Object)(object)targetCollider != (Object)null) { targetCollider.enabled = false; } SailpackRecord sailpackRecord = SailpackRecord.FromSail(sail, mast); Vector3 heldPosition = SailpackPickupHandoff.GetHeldPosition(activatingPointer, 1.25f, 0f); Quaternion heldRotation = SailpackPickupHandoff.GetHeldRotation(activatingPointer, 180f); SailpackData sailpackData = SailpackFactory.CreateStaged(sailpackRecord, heldPosition, heldRotation, registerToSave: true, mast); if ((Object)(object)sailpackData == (Object)null) { removalInProgress = false; NotificationUi instance = NotificationUi.instance; if (instance != null) { instance.ShowNotification("Could not create a sail package; the sail was not removed."); } return; } ShipItem component = ((Component)sailpackData).GetComponent<ShipItem>(); if ((Object)(object)component == (Object)null) { SailpackFactory.DiscardStaged(sailpackData, unregisterFromSave: true); removalInProgress = false; NotificationUi instance2 = NotificationUi.instance; if (instance2 != null) { instance2.ShowNotification("Could not create a usable sail package; the sail was not removed."); } return; } if (!StaysailDetacher.TryDetach(mast, sail, out var error)) { SailpackFactory.DiscardStaged(sailpackData, unregisterFromSave: true); removalInProgress = false; NotificationUi instance3 = NotificationUi.instance; if (instance3 != null) { instance3.ShowNotification(error); } return; } SailpackFactory.ActivateStaged(sailpackData); StaysailInteractionVisuals.ResetAfterInteraction(); SailpackPickupHandoff.Schedule(activatingPointer, component, sailpackRecord); ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogInfo((object)("Removed " + sailpackRecord.GetDisplayName() + " into a saved sail package; player handoff scheduled.")); } } private bool CanRemove() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Invalid comparison between Unknown and I4 if ((Object)(object)mast != (Object)null && (Object)(object)sail != (Object)null && sail.IsInstalled() && (Object)(object)GameState.currentShipyard == (Object)null && !GameState.sleeping && !Object.op_Implicit((Object)(object)GameState.inBed) && !BoatCamera.on && StaysailTargets.IsEligible(mast) && (int)sail.category == 5) { return sail.currentUnroll <= 0.001f; } return false; } private void OnDisable() { ResetInteractionVisuals(); } private void OnDestroy() { Instances.Remove(this); } } internal sealed class FurledStaysailHitbox : MonoBehaviour { internal Collider Collider { get; private set; } internal void Set(Collider collider) { Collider = collider; } } internal static class StaysailTargets { internal static bool IsEligible(Mast mast) { if ((Object)(object)mast != (Object)null && mast.onlyStaysails) { return !IsBermudaMast(mast); } return false; } internal static bool IsBermudaMast(Mast mast) { if ((Object)(object)mast == (Object)null) { return false; } BoatPartOption component = ((Component)mast).GetComponent<BoatPartOption>(); string text = (((Object)(object)component != (Object)null && !string.IsNullOrEmpty(component.optionName)) ? component.optionName : ((Object)((Component)mast).gameObject).name); text = text.ToLowerInvariant().Replace('_', ' '); if (text.Contains("bermuda") && text.Contains("mast")) { return !text.Contains("stay"); } return false; } internal static int GetBoatSceneIndex(Mast mast) { if ((Object)(object)mast == (Object)null) { return -1; } SaveableObject val = null; if ((Object)(object)mast.shipRigidbody != (Object)null) { val = ((Component)mast.shipRigidbody).GetComponent<SaveableObject>() ?? ((Component)mast.shipRigidbody).GetComponentInParent<SaveableObject>(); } val = val ?? ((Component)mast).GetComponentInParent<SaveableObject>(); if (!((Object)(object)val != (Object)null)) { return -1; } return val.sceneIndex; } internal static string GetStayName(Mast mast) { if ((Object)(object)mast == (Object)null) { return "Staysail stay"; } BoatPartOption component = ((Component)mast).GetComponent<BoatPartOption>(); string text = (((Object)(object)component != (Object)null && !string.IsNullOrEmpty(component.optionName)) ? component.optionName : ((Object)((Component)mast).gameObject).name); text = text.Replace('_', ' ').Trim(); if (!string.IsNullOrEmpty(text)) { return text; } return "Staysail stay"; } internal static Mast Resolve(SailpackData data) { SailpackRecord record = data?.Record; if (record == null) { return null; } if (Matches(data.RuntimeTarget, record)) { return data.RuntimeTarget; } Mast[] array = Array.Empty<Mast>(); SaveLoadManager instance = SaveLoadManager.instance; if ((Object)(object)instance != (Object)null) { SaveableObject[] currentObjects = instance.GetCurrentObjects(); int targetBoatSceneIndex = record.targetBoatSceneIndex; if (currentObjects != null && targetBoatSceneIndex >= 0 && targetBoatSceneIndex < currentObjects.Length && (Object)(object)currentObjects[targetBoatSceneIndex] != (Object)null) { array = (from mast in ((Component)currentObjects[targetBoatSceneIndex]).GetComponentsInChildren<Mast>(false) where Matches(mast, record) select mast).ToArray(); } } if (array.Length == 0) { array = (from mast in Object.FindObjectsOfType<Mast>() where Matches(mast, record) select mast).ToArray(); } Mast val = ((IEnumerable<Mast>)array).FirstOrDefault((Func<Mast, bool>)((Mast mast) => string.Equals(GetStayName(mast), record.targetStayName, StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val == (Object)null && array.Length == 1) { val = array[0]; } if ((Object)(object)val != (Object)null) { data.BindTarget(val); } return val; } private static bool Matches(Mast mast, SailpackRecord record) { if ((Object)(object)mast != (Object)null && ((Component)mast).gameObject.activeInHierarchy && IsEligible(mast) && GetBoatSceneIndex(mast) == record.targetBoatSceneIndex) { return mast.orderIndex == record.targetMastOrderIndex; } return false; } internal static void EnsureRuntimeButtons(Mast mast) { if (!IsEligible(mast)) { return; } foreach (GameObject item in mast.sails ?? new List<GameObject>()) { EnsureRemovalButton(mast, item); } } internal static void EnsureRemovalButton(Mast mast, GameObject sailObject) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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) Sail val = (((Object)(object)sailObject != (Object)null) ? sailObject.GetComponent<Sail>() : null); if (!IsEligible(mast) || (Object)(object)val == (Object)null || (int)val.category != 5) { return; } ReefEffectAnimUniversal componentInChildren = ((Component)val).GetComponentInChildren<ReefEffectAnimUniversal>(true); Renderer val2 = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.furledSail : null); if ((Object)(object)val2 == (Object)null) { return; } FurledStaysailButton component = ((Component)val2).GetComponent<FurledStaysailButton>(); if ((Object)(object)component == (Object)null) { BoxCollider val3 = ((Component)val2).gameObject.AddComponent<BoxCollider>(); MeshFilter component2 = ((Component)val2).GetComponent<MeshFilter>(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.sharedMesh != (Object)null) { Bounds bounds = component2.sharedMesh.bounds; val3.center = ((Bounds)(ref bounds)).center; bounds = component2.sharedMesh.bounds; val3.size = ((Bounds)(ref bounds)).size; } ((Collider)val3).isTrigger = true; ((Component)val2).gameObject.AddComponent<FurledStaysailHitbox>().Set((Collider)(object)val3); component = ((Component)val2).gameObject.AddComponent<FurledStaysailButton>(); component.Initialize(mast, val, (Collider)(object)val3); } else { component.Initialize(mast, val); } } } internal static class StaysailWindShadow { private static readonly FieldInfo CheckingField = AccessTools.Field(typeof(SailShadowCol), "checking") ?? throw new MissingFieldException(typeof(SailShadowCol).FullName, "checking"); internal static bool AppliesTo(Sail sail) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 if ((Object)(object)sail != (Object)null && sail.IsInstalled() && (int)sail.category == 5) { return StaysailTargets.IsEligible(((Component)sail).GetComponentInParent<Mast>()); } return false; } internal static void RecoverAfterHingeReset(Sail sail) { if (AppliesTo(sail)) { SailShadowCol componentInChildren = ((Component)sail).GetComponentInChildren<SailShadowCol>(true); if ((Object)(object)componentInChildren != (Object)null) { CheckingField.SetValue(componentInChildren, false); } } } } [HarmonyPatch(typeof(Sail), "GetCurrentShadowMult")] internal static class StaysailWindReceptionPatch { [HarmonyPostfix] private static void Postfix(Sail __instance, ref float __result) { if (StaysailWindShadow.AppliesTo(__instance)) { __result = 1f; } } } [HarmonyPatch(typeof(JibAngleMaster), "ResetHingeRestingRot")] internal static class StaysailShadowHingeResetPatch { [HarmonyPostfix] private static void Postfix(JibAngleMaster __instance) { StaysailWindShadow.RecoverAfterHingeReset(((Component)__instance).GetComponent<Sail>()); } } [HarmonyPatch(typeof(SaveableBoatCustomization), "GetData")] internal static class ExcludeSailmakerPreviewsFromSavePatch { [HarmonyPostfix] private static void Postfix(SaveableBoatCustomization __instance, SaveBoatCustomizationData __result) { if (__result?.sails == null || SailmakerSession.GetPreviews().Count == 0) { return; } BoatRefs component = ((Component)__instance).GetComponent<BoatRefs>(); if (component?.masts == null) { return; } List<int> list = new List<int>(); int num = 0; Mast[] masts = component.masts; foreach (Mast val in masts) { if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeSelf || val.sails == null) { continue; } foreach (GameObject sail in val.sails) { if (SailmakerSession.IsPreview(((Object)(object)sail != (Object)null) ? sail.GetComponent<Sail>() : null)) { list.Add(num); } num++; } } for (int num2 = list.Count - 1; num2 >= 0; num2--) { int num3 = list[num2]; if (num3 >= 0 && num3 < __result.sails.Count) { __result.sails.RemoveAt(num3); } } } } [HarmonyPatch(typeof(ShipyardDocuments), "Update")] internal static class SailmakerDeliveryPointPatch { [HarmonyPostfix] private static void Postfix(ShipyardDocuments __instance) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_005d: 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_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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.shipyard == (Object)null || (Object)(object)((Component)__instance).GetComponent<SailmakerDeliveryInstalled>() != (Object)null) { return; } ((Component)__instance).gameObject.AddComponent<SailmakerDeliveryInstalled>(); try { Transform transform = ((Component)__instance).transform; GameObject val = new GameObject("sail maker delivery anchor"); val.transform.SetParent(transform.parent, false); val.transform.localScale = transform.localScale; val.transform.rotation = transform.rotation; Scene scene = ((Component)__instance).gameObject.scene; if (TryGetAuthoredPose(((Scene)(ref scene)).name, out var localPosition, out var localEulerAngles)) { val.transform.position = transform.TransformPoint(localPosition); val.transform.rotation = transform.rotation * Quaternion.Euler(localEulerAngles); } else { val.transform.position = transform.position + GetFallbackOffset(((Component)__instance).GetComponent<Collider>(), transform); } GameObject val2 = new GameObject("sail package delivery point"); val2.transform.SetParent(val.transform, false); val2.transform.localPosition = new Vector3(0f, 0.55f, 0.8f); SailmakerSession.RegisterDeliveryPoint(__instance.shipyard, val2.transform); } catch (Exception arg) { ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogError((object)$"Could not create the Sail Maker delivery point: {arg}"); } } } private static Vector3 GetFallbackOffset(Collider collider, Transform source) { //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_000a: 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_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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) Vector3 surfaceLateral = GetSurfaceLateral(collider, source); Vector3 val = surfaceLateral * (GetProjectedHalfExtent(collider, surfaceLateral) * 2f + 0.45f); if ((Object)(object)collider == (Object)null) { return val; } Bounds bounds = collider.bounds; Bounds val2 = bounds; for (int i = 0; i < 8; i++) { ((Bounds)(ref val2)).center = ((Bounds)(ref bounds)).center + val; if (!((Bounds)(ref bounds)).Intersects(val2)) { break; } val += surfaceLateral * 0.25f; } return val; } private static bool TryGetAuthoredPose(string sceneName, out Vector3 localPosition, out Vector3 localEulerAngles) { //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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_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_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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) switch (sceneName) { case "island 1 A Gold Rock": localPosition = new Vector3(-0.646f, -0.66f, 0f); localEulerAngles = new Vector3(-1.716f, 0f, -27.634f); return true; case "island 9 E Dragon Cliffs": localPosition = new Vector3(-0.267f, -0.758f, 0f); localEulerAngles = new Vector3(0f, 0f, 20.456f); return true; case "island 15 M (Fort)": localPosition = new Vector3(-0.993f, -1.933f, 0f); localEulerAngles = new Vector3(0f, 0f, -15.067f); return true; default: localPosition = Vector3.zero; localEulerAngles = Vector3.zero; return false; case "island 27 Lagoon SwampShipyard": localPosition = new Vector3(-0.699f, -0.891f, 0f); localEulerAngles = new Vector3(0f, 0f, -157.151f); return true; } } private static float GetProjectedHalfExtent(Collider collider, Vector3 direction) { //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_0018: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_004b: 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) if ((Object)(object)collider == (Object)null) { return 0.6f; } Bounds bounds = collider.bounds; Vector3 extents = ((Bounds)(ref bounds)).extents; Vector3 normalized = ((Vector3)(ref direction)).normalized; return Mathf.Abs(normalized.x) * extents.x + Mathf.Abs(normalized.y) * extents.y + Mathf.Abs(normalized.z) * extents.z; } private static Vector3 GetSurfaceLateral(Collider collider, Transform source) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_001e: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_0049: 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_0032: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) Vector3 val = source.forward; BoxCollider val2 = (BoxCollider)(object)((collider is BoxCollider) ? collider : null); if ((Object)(object)val2 != (Object)null) { Vector3 size = val2.size; if (size.x <= size.y && size.x <= size.z) { val = source.right; } else if (size.y <= size.x && size.y <= size.z) { val = source.up; } } Vector3 val3 = Vector3.Cross(Vector3.up, val); if (((Vector3)(ref val3)).sqrMagnitude < 0.01f) { val3 = Vector3.ProjectOnPlane(source.right, Vector3.up); } if (((Vector3)(ref val3)).sqrMagnitude < 0.01f) { val3 = source.right; } ((Vector3)(ref val3)).Normalize(); if (Vector3.Dot(val3, source.right) < 0f) { val3 = -val3; } return val3; } } internal sealed class SailmakerDeliveryInstalled : MonoBehaviour { } [HarmonyPatch(typeof(ShipyardUI), "Awake")] internal static class SailmakerModeButtonInstallPatch { private const float GapAboveCleanShip = 0.3f; [HarmonyPostfix] private static void Postfix(ShipyardUI __instance) { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) try { ShipyardButton val = ((IEnumerable<ShipyardButton>)((Component)__instance).GetComponentsInChildren<ShipyardButton>(true)).FirstOrDefault((Func<ShipyardButton, bool>)((ShipyardButton button) => (int)button.function == 12)); if ((Object)(object)val == (Object)null) { ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogError((object)"Could not find the shipyard's Clean Ship button; the Sail Maker button was not added."); } return; } Transform transform = ((Component)val).transform; GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, transform.parent); ((Object)val2).name = "shipyard ui button sail maker"; ShipyardButton[] componentsInChildren = val2.GetComponentsInChildren<ShipyardButton>(true); for (int num = 0; num < componentsInChildren.Length; num++) { Object.DestroyImmediate((Object)(object)componentsInChildren[num]); } Outline[] componentsInChildren2 = val2.GetComponentsInChildren<Outline>(true); for (int num2 = 0; num2 < componentsInChildren2.Length; num2++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[num2]); } val2.transform.localRotation = transform.localRotation; val2.transform.localScale = transform.localScale; val2.transform.localPosition = transform.localPosition + Vector3.up * (transform.localScale.y + 0.3f); TextMesh text = ((val2.transform.childCount > 0) ? ((Component)val2.transform.GetChild(0)).GetComponent<TextMesh>() : null); val2.AddComponent<SailmakerModeButton>().Initialize(text); } catch (Exception arg) { ManualLogSource log2 = SwappableStaysailPlugin.Log; if (log2 != null) { log2.LogError((object)$"Could not add the Sail Maker button: {arg}"); } } } } [HarmonyPatch(typeof(ShipyardDocuments), "OnActivate")] internal static class NormalShipyardEntryPatch { [HarmonyPrefix] private static void Prefix() { SailmakerSession.End(); } } [HarmonyPatch(typeof(Shipyard), "ActivateDocuments")] internal static class ShipyardActivatePatch { [HarmonyPrefix] private static void Prefix() { StaysailInteractionVisuals.ResetForShipyard(); } [HarmonyPostfix] private static void Postfix(Shipyard __instance) { SailmakerSession.TryBegin(__instance); } } [HarmonyPatch(typeof(Shipyard), "DischargeShip")] internal static class ShipyardDischargePatch { [HarmonyPrefix] private static void Prefix(Shipyard __instance) { SailmakerCollisionChecks.Cancel(__instance.sailInstaller); SailmakerSession.End(); } [HarmonyPostfix] private static void Postfix(Shipyard __instance) { SailmakerCollisionChecks.Cancel(__instance.sailInstaller); } } [HarmonyPatch(typeof(ShipyardSailInstaller), "RecheckAllSailsCols")] internal static class ShipyardCollisionRecheckPatch { [HarmonyPrefix] private static bool Prefix(ShipyardSailInstaller __instance, Shipyard ___shipyard) { SailmakerCollisionChecks.Request(__instance, ___shipyard); return false; } } internal sealed class SailmakerCollisionChecks : MonoBehaviour { private Shipyard shipyard; private GameObject boat; private Coroutine worker; private int revision; private bool ready; internal static void Request(ShipyardSailInstaller installer, Shipyard yard) { if ((Object)(object)installer == (Object)null) { return; } SailmakerCollisionChecks sailmakerCollisionChecks = ((Component)installer).GetComponent<SailmakerCollisionChecks>(); if ((Object)(object)yard == (Object)null || (Object)(object)GameState.currentShipyard != (Object)(object)yard || (Object)(object)yard.GetCurrentBoat() == (Object)null) { if ((Object)(object)sailmakerCollisionChecks != (Object)null) { sailmakerCollisionChecks.Stop(); } return; } if ((Object)(object)sailmakerCollisionChecks == (Object)null) { sailmakerCollisionChecks = ((Component)installer).gameObject.AddComponent<SailmakerCollisionChecks>(); } sailmakerCollisionChecks.Stop(); sailmakerCollisionChecks.shipyard = yard; sailmakerCollisionChecks.boat = yard.GetCurrentBoat(); sailmakerCollisionChecks.worker = ((MonoBehaviour)sailmakerCollisionChecks).StartCoroutine(sailmakerCollisionChecks.Check(sailmakerCollisionChecks.revision)); } internal static bool IsReady(Shipyard yard) { SailmakerCollisionChecks sailmakerCollisionChecks = (((Object)(object)yard != (Object)null && (Object)(object)yard.sailInstaller != (Object)null) ? ((Component)yard.sailInstaller).GetComponent<SailmakerCollisionChecks>() : null); if ((Object)(object)sailmakerCollisionChecks != (Object)null && sailmakerCollisionChecks.ready) { return sailmakerCollisionChecks.IsCurrent(sailmakerCollisionChecks.revision); } return false; } internal static void Cancel(ShipyardSailInstaller installer) { SailmakerCollisionChecks sailmakerCollisionChecks = (((Object)(object)installer != (Object)null) ? ((Component)installer).GetComponent<SailmakerCollisionChecks>() : null); if ((Object)(object)sailmakerCollisionChecks != (Object)null) { sailmakerCollisionChecks.Stop(); } } private void Stop() { revision++; ready = false; if (worker != null) { ((MonoBehaviour)this).StopCoroutine(worker); } worker = null; shipyard = null; boat = null; } private bool IsCurrent(int request) { if (request == revision && (Object)(object)shipyard != (Object)null && (Object)(object)boat != (Object)null && (Object)(object)GameState.currentShipyard == (Object)(object)shipyard) { return (Object)(object)shipyard.GetCurrentBoat() == (Object)(object)boat; } return false; } private IEnumerator Check(int request) { yield return (object)new WaitForEndOfFrame(); yield return (object)new WaitForEndOfFrame(); yield return (object)new WaitForFixedUpdate(); yield return (object)new WaitForFixedUpdate(); yield return (object)new WaitForFixedUpdate(); if (!IsCurrent(request)) { yield break; } BoatRefs component = boat.GetComponent<BoatRefs>(); if ((Object)(object)component == (Object)null || component.masts == null) { yield break; } Sail[] array = (from s in component.masts.Where((Mast m) => (Object)(object)m != (Object)null && ((Component)m).gameObject.activeInHierarchy && m.sails != null).SelectMany((Mast m) => m.sails.ToArray()) where (Object)(object)s != (Object)null && s.activeInHierarchy select s.GetComponent<Sail>() into s where (Object)(object)s != (Object)null select s).ToArray(); List<ShipyardSailColChecker> checkers = new List<ShipyardSailColChecker>(); Sail[] array2 = array; foreach (Sail val in array2) { if (!IsCurrent(request) || (Object)(object)val == (Object)null) { yield break; } SailConnections component2 = ((Component)val).GetComponent<SailConnections>(); ShipyardSailColChecker val2 = (((Object)(object)component2 != (Object)null) ? component2.colChecker : null); if ((Object)(object)val2 == (Object)null) { yield break; } checkers.Add(val2); val2.RunColCheck(); yield return (object)new WaitForFixedUpdate(); yield return (object)new WaitForEndOfFrame(); } while (IsCurrent(request) && checkers.Any((ShipyardSailColChecker c) => (Object)(object)c != (Object)null && c.checking)) { yield return (object)new WaitForFixedUpdate(); } yield return (object)new WaitForFixedUpdate(); yield return (object)new WaitForEndOfFrame(); if (IsCurrent(request) && !checkers.Any((ShipyardSailColChecker c) => (Object)(object)c == (Object)null || c.checking || !c.readyToInstall)) { ready = true; worker = null; shipyard.UpdateOrder(); if ((Object)(object)ShipyardUI.instance != (Object)null) { ShipyardUI.instance.RefreshButtons(); } } } private void OnDisable() { Stop(); } } [HarmonyPatch(typeof(Shipyard), "CancelOrder")] internal static class ShipyardCancelPatch { [HarmonyPrefix] private static bool Prefix() { if (SailmakerSession.Active) { SailmakerSession.Cancel(); return false; } return true; } } [HarmonyPatch(typeof(Shipyard), "SelectMast")] internal static class ShipyardSelectMastPatch { [HarmonyPrefix] private static bool Prefix(Shipyard __instance, int index) { if (!SailmakerSession.Active) { return true; } GameObject currentBoat = __instance.GetCurrentBoat(); BoatRefs val = ((currentBoat != null) ? currentBoat.GetComponent<BoatRefs>() : null); if (!SailmakerSession.IsAllowedMast((val?.masts != null && index >= 0 && index < val.masts.Length) ? val.masts[index] : null)) { NotificationUi instance = NotificationUi.instance; if (instance != null) { instance.ShowNotification("Select a supported staysail stay."); } return false; } return true; } } [HarmonyPatch(typeof(Shipyard), "SelectSail")] internal static class ShipyardSelectSailPatch { [HarmonyPrefix] private static bool Prefix(Shipyard __instance, int index) { if (!SailmakerSession.Active) { return true; } SailmakerSession.SelectPreview(index); return false; } } [HarmonyPatch(typeof(Shipyard), "AddNewSail")] internal static class ShipyardAddSailPatch { [HarmonyPrefix] private static bool Prefix(Shipyard __instance, GameObject prefab) { if (!SailmakerSession.Active) { return true; } if (!SailmakerSession.IsAllowedMast(__instance.sailInstaller.GetCurrentMast()) || !SailmakerSession.IsAllowedSailPrefab(prefab)) { NotificationUi instance = NotificationUi.instance; if (instance != null) { instance.ShowNotification("Swappable Staysail only accepts staysails on supported stays."); } return false; } SailmakerSession.AddPreview(prefab); return false; } } [HarmonyPatch(typeof(Shipyard), "RemoveSelectedSail")] internal static class ShipyardRemoveSailPatch { [HarmonyPrefix] private static bool Prefix() { if (!SailmakerSession.Active) { return true; } SailmakerSession.RemoveSelectedPreview(); return false; } } [HarmonyPatch(typeof(ShipyardSailInstaller), "ApplySailPosition")] internal static class SailmakerApplyPositionSafetyPatch { [HarmonyPrefix] private static bool Prefix(ShipyardSailInstaller __instance) { if ((Object)(object)GameState.currentShipyard != (Object)null && (Object)(object)__instance.GetCurrentMast() != (Object)null) { return (Object)(object)__instance.GetCurrentSail() != (Object)null; } return false; } } [HarmonyPatch(typeof(Shipyard), "UpdateOrder", new Type[] { typeof(bool) })] internal static class ShipyardOrderPatch { [HarmonyPrefix] private static bool Prefix(Shipyard __instance) { return !SailmakerSession.RefreshOrder(__instance); } } [HarmonyPatch(typeof(Shipyard), "ConfirmOrder")] internal static class ShipyardConfirmPatch { [HarmonyPrefix] private static bool Prefix() { if (!SailmakerSession.Active) { return true; } SailmakerSession.Buy(); return false; } } [HarmonyPatch(typeof(ShipyardUI), "SailMastCompatible")] internal static class SailCompatibilityPatch { [HarmonyPostfix] private static void Postfix(ref bool __result, GameObject sailPrefab) { if (SailmakerSession.Active) { Shipyard currentShipyard = GameState.currentShipyard; Mast mast = ((currentShipyard != null) ? currentShipyard.sailInstaller.GetCurrentMast() : null); __result = SailmakerSession.IsAllowedMast(mast) && SailmakerSession.IsAllowedSailPrefab(sailPrefab); } } } [HarmonyPatch(typeof(ShipyardButton), "OnActivate")] internal static class SailmakerButtonGuardPatch { [HarmonyPrefix] private static bool Prefix(ShipyardButton __instance) { //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_0012: Invalid comparison between Unknown and I4 //IL_0014: 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_0019: Invalid comparison between Unknown and I4 //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 if (!SailmakerSession.Active) { return true; } ButtonFunction function = __instance.function; if ((int)function != 2) { if (function - 12 <= 3 || (int)function == 18) { return false; } return true; } return __instance.index == 5; } } [HarmonyPatch(typeof(ShipyardUI), "UpdateMastSailsList")] internal static class SailmakerSailListPatch { [HarmonyPrefix] private static bool Prefix(ShipyardUI __instance) { if (!SailmakerSession.Active) { return true; } SailmakerSession.RenderPreviewList(__instance); return false; } } [HarmonyPatch(typeof(ShipyardUI), "UpdateButtonSelections")] internal static class SailmakerSelectionPatch { [HarmonyPostfix] private static void Postfix(ShipyardUI __instance) { if (SailmakerSession.Active) { SailmakerSession.RenderPreviewSelections(__instance); } } } [HarmonyPatch(typeof(ShipyardUI), "UpdateSailsCountText")] internal static class SailmakerSailCountPatch { [HarmonyPrefix] private static bool Prefix(ShipyardUI __instance) { if (!SailmakerSession.Active) { return true; } SailmakerSession.HideSailCount(__instance); return false; } } [HarmonyPatch(typeof(ShipyardUI), "RefreshButtons")] internal static class SailmakerUiPatch { private sealed class ButtonLayoutState { private const float ConfirmWidthMultiplier = 1.45f; private const float CancelLeftOffset = 0.55f; private readonly Transform button; private readonly Transform label; private readonly Vector3 buttonLocalPosition; private readonly Vector3 buttonLocalScale; private readonly Vector3 labelLocalScale; internal ButtonLayoutState(ShipyardButton source) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) button = (((Object)(object)source != (Object)null) ? ((Component)source).transform : null); label = (((Object)(object)button != (Object)null && button.childCount > 0) ? button.GetChild(0) : null); buttonLocalPosition = (((Object)(object)button != (Object)null) ? button.localPosition : Vector3.zero); buttonLocalScale = (((Object)(object)button != (Object)null) ? button.localScale : Vector3.one); labelLocalScale = (((Object)(object)label != (Object)null) ? label.localScale : Vector3.one); } internal void ApplyConfirm() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)button == (Object)null)) { button.localScale = new Vector3(buttonLocalScale.x * 1.45f, buttonLocalScale.y, buttonLocalScale.z); if ((Object)(object)label != (Object)null) { label.localScale = new Vector3(labelLocalScale.x / 1.45f, labelLocalScale.y, labelLocalScale.z); } } } internal void ApplyCancel() { //IL_0015: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)button != (Object)null) { button.localPosition = buttonLocalPosition + Vector3.left * 0.55f; } } internal void Restore() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)button != (Object)null) { button.localPosition = buttonLocalPosition; button.localScale = buttonLocalScale; } if ((Object)(object)label != (Object)null) { label.localScale = labelLocalScale; } } } private static readonly Dictionary<Collider, bool> ColliderStates = new Dictionary<Collider, bool>(); private static readonly Dictionary<Renderer, Material> RendererStates = new Dictionary<Renderer, Material>(); private static readonly Dictionary<ShipyardButton, string> ButtonTexts = new Dictionary<ShipyardButton, string>(); private static readonly Dictionary<ShipyardButton, ButtonLayoutState> ButtonLayouts = new Dictionary<ShipyardButton, ButtonLayoutState>(); [HarmonyPostfix] private static void Postfix(ShipyardUI __instance) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Invalid comparison between Unknown and I4 //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Invalid comparison between Unknown and I4 //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Invalid comparison between Unknown and I4 //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Invalid comparison between Unknown and I4 if (!SailmakerSession.Active) { RestoreUi(); return; } int count = SailmakerSession.GetPreviews().Count; ShipyardButton[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<ShipyardButton>(true); foreach (ShipyardButton val in componentsInChildren) { bool num = (int)val.function == 12 || (int)val.function == 18 || (int)val.function == 13 || (int)val.function == 14 || (int)val.function == 15 || ((int)val.function == 2 && val.index != 5); Collider component = ((Component)val).GetComponent<Collider>(); Renderer component2 = ((Component)val).GetComponent<Renderer>(); if (num) { if ((Object)(object)component != (Object)null) { if (!ColliderStates.ContainsKey(component)) { ColliderStates[component] = component.enabled; } component.enabled = false; } if ((Object)(object)component2 != (Object)null) { if (!RendererStates.ContainsKey(component2)) { RendererStates[component2] = component2.sharedMaterial; } component2.sharedMaterial = __instance.darkParchmentMaterial; } } if ((int)val.function == 8) { if (!ButtonTexts.ContainsKey(val) && ((Component)val).transform.childCount > 0) { TextMesh component3 = ((Component)((Component)val).transform.GetChild(0)).GetComponent<TextMesh>(); if ((Object)(object)component3 != (Object)null) { ButtonTexts[val] = component3.text; } } val.SetText($"Buy Staysails ({count})"); GetLayout(val).ApplyConfirm(); } else if ((int)val.function == 9) { GetLayout(val).ApplyCancel(); } } } private static ButtonLayoutState GetLayout(ShipyardButton button) { if (!ButtonLayouts.TryGetValue(button, out var value)) { value = new ButtonLayoutState(button); ButtonLayouts[button] = value; } return value; } internal static void RestoreUi() { foreach (KeyValuePair<Collider, bool> colliderState in ColliderStates) { if ((Object)(object)colliderState.Key != (Object)null) { colliderState.Key.enabled = colliderState.Value; } } foreach (KeyValuePair<Renderer, Material> rendererState in RendererStates) { if ((Object)(object)rendererState.Key != (Object)null) { rendererState.Key.sharedMaterial = rendererState.Value; } } foreach (KeyValuePair<ShipyardButton, string> buttonText in ButtonTexts) { if ((Object)(object)buttonText.Key != (Object)null) { buttonText.Key.SetText(buttonText.Value); } } foreach (ButtonLayoutState value in ButtonLayouts.Values) { value.Restore(); } ColliderStates.Clear(); RendererStates.Clear(); ButtonTexts.Clear(); ButtonLayouts.Clear(); } } [HarmonyPatch(typeof(WindCloth), "Update")] internal static class SailmakerHiddenClothPatch { [HarmonyPostfix] private static void Postfix(Sail ___sail, Renderer ___renderer) { if ((Object)(object)___renderer != (Object)null && SailmakerSession.IsHiddenSail(___sail)) { ___renderer.enabled = false; } } } [HarmonyPatch(typeof(ShipyardSailColChecker), "OnTriggerEnter")] internal static class SailmakerPreviewCollisionPatch { private static readonly FieldInfo SailField = AccessTools.Field(typeof(ShipyardSailColChecker), "sail"); [HarmonyPostfix] private static void Postfix(ShipyardSailColChecker __instance, Collider other, Sail ___sail) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Invalid comparison between Unknown and I4 if (!SailmakerSession.Active || (Object)(object)other == (Object)null || __instance.currentAngle != 0 || ((Component)__instance).transform.position.y >= 900f || !SailmakerSession.IsPreview(___sail)) { return; } GameObject gameObject = ((Component)other).gameObject; if (gameObject.CompareTag("SailColCheckerSub") && (Object)(object)gameObject.transform.parent != (Object)null) { gameObject = ((Component)gameObject.transform.parent).gameObject; } if (!((Object)(object)gameObject == (Object)(object)((Component)__instance).gameObject) && gameObject.CompareTag("SailColChecker")) { ShipyardSailColChecker component = gameObject.GetComponent<ShipyardSailColChecker>(); Sail val; if (!((Object)(object)component != (Object)null)) { val = null; } else { FieldInfo sailField = SailField; object? obj = ((sailField != null) ? sailField.GetValue(component) : null); val = (Sail)((obj is Sail) ? obj : null); } Sail val2 = val; if (!((Object)(object)component == (Object)null) && component.currentAngle == 0 && !((Object)(object)val2 == (Object)null) && (int)val2.category != 5) { __instance.collisionsWithSails++; SailmakerSession.RefreshOrder(GameState.currentShipyard); } } } } internal static class SailmakerSession { private static readonly FieldInfo CurrentOrderTotalField = AccessTools.Field(typeof(Shipyard), "currentOrderTotal"); private static readonly FieldInfo CurrentOrderTextField = AccessTools.Field(typeof(Shipyard), "currentOrderText"); private static readonly FieldInfo InstallErrorField = AccessTools.Field(typeof(Shipyard), "installError"); private static readonly FieldInfo SelectSailButtonsField = AccessTools.Field(typeof(ShipyardUI), "selectSailButtons"); private static readonly FieldInfo SailCountTextField = AccessTools.Field(typeof(ShipyardUI), "sailCountText"); private static readonly Dictionary<Shipyard, Transform> DeliveryPoints = new Dictionary<Shipyard, Transform>(); private static readonly List<SailmakerPreview> Previews = new List<SailmakerPreview>(); private static readonly Dictionary<Mast, SailmakerMastRigState> RigStates = new Dictionary<Mast, SailmakerMastRigState>(); private static readonly HashSet<Sail> HiddenSails = new HashSet<Sail>(); private static readonly Dictionary<Renderer, bool> HiddenClothRenderers = new Dictionary<Renderer, bool>(); internal static bool Pending { get; private set; } internal static Shipyard ActiveShipyard { get; private set; } internal static bool Active { get { if ((Object)(object)ActiveShipyard != (Object)null) { return (Object)(object)GameState.currentShipyard == (Object)(object)ActiveShipyard; } return false; } } internal static void RegisterDeliveryPoint(Shipyard shipyard, Transform point) { PruneDeliveryPoints(); if ((Object)(object)shipyard != (Object)null && (Object)(object)point != (Object)null) { DeliveryPoints[shipyard] = point; } } internal static void Request(Shipyard shipyard) { Pending = (Object)(object)shipyard != (Object)null; } internal static void TryBegin(Shipyard shipyard) { if (Pending && !((Object)(object)shipyard == (Object)null) && !((Object)(object)GameState.currentShipyard != (Object)(object)shipyard)) { StayInstallTargeting.Deactivate(); Pending = false; ActiveShipyard = shipyard; ClearPreviews(refresh: false); HideInstalledSails(shipyard); ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogInfo((object)$"Opened Sail Maker at shipyard region {shipyard.region}."); } RefreshOrder(shipyard); ShipyardUI instance = ShipyardUI.instance; if ((Object)(object)instance != (Object)null) { instance.ChangeMenuCategory(-1); instance.CloseSailCategoryMenu(); instance.HideNewSailButtons(); instance.RefreshButtons(); } } } internal static void End() { Pending = false; StayInstallTargeting.Deactivate(); try { ClearPreviews(refresh: false); } catch (Exception arg) { ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogError((object)$"Sail Maker cleanup failed during exit: {arg}"); } } finally { ShowInstalledSails(); ActiveShipyard = null; SailmakerUiPatch.RestoreUi(); } } internal static bool IsHiddenSail(Sail sail) { if (HiddenSails.Count > 0 && (Object)(object)sail != (Object)null) { return HiddenSails.Contains(sail); } return false; } private static void HideInstalledSails(Shipyard shipyard) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Invalid comparison between Unknown and I4 ShowInstalledSails(); GameObject currentBoat = shipyard.GetCurrentBoat(); BoatRefs val = (((Object)(object)currentBoat != (Object)null) ? currentBoat.GetComponent<BoatRefs>() : null); if ((((Object)(object)val != (Object)null) ? val.masts : null) == null) { return; } Mast[] masts = val.masts; foreach (Mast val2 in masts) { if ((Object)(object)val2 == (Object)null || val2.sails == null) { continue; } foreach (GameObject sail in val2.sails) { Sail val3 = (((Object)(object)sail != (Object)null) ? sail.GetComponent<Sail>() : null); if ((Object)(object)val3 == (Object)null || (int)val3.category != 5 || IsPreview(val3)) { continue; } HiddenSails.Add(val3); WindCloth[] componentsInChildren = sail.GetComponentsInChildren<WindCloth>(true); for (int j = 0; j < componentsInChildren.Length; j++) { Renderer component = ((Component)componentsInChildren[j]).GetComponent<Renderer>(); if ((Object)(object)component != (Object)null && !HiddenClothRenderers.ContainsKey(component)) { HiddenClothRenderers[component] = component.enabled; component.enabled = false; } } } } } private static void ShowInstalledSails() { foreach (KeyValuePair<Renderer, bool> hiddenClothRenderer in HiddenClothRenderers) { if ((Object)(object)hiddenClothRenderer.Key != (Object)null) { hiddenClothRenderer.Key.enabled = hiddenClothRenderer.Value; } } HiddenClothRenderers.Clear(); HiddenSails.Clear(); } internal static void ToggleFromShipyardMenu() { Shipyard currentShipyard = GameState.currentShipyard; if ((Object)(object)currentShipyard == (Object)null || (Object)(object)currentShipyard.GetCurrentBoat() == (Object)null) { return; } if (Active) { if (GetPreviews().Count > 0) { Notify("Buy or cancel the\nstaysails first."); return; } End(); ShowSailPage(currentShipyard); currentShipyard.UpdateOrder(); ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogInfo((object)"Switched from Sail Maker back to the shipyard."); } } else if (HasUnconfirmedShipyardOrder(currentShipyard)) { Notify("Confirm or cancel the\ncurrent order first."); } else if (!HasSupportedStay(currentShipyard.GetCurrentBoat())) { Notify("This ship has no\nsupported staysail stay."); } else { currentShipyard.sailInstaller.SelectMast((Mast)null); Request(currentShipyard); TryBegin(currentShipyard); } } private static void ShowSailPage(Shipyard shipyard) { shipyard.sailInstaller.SelectMast((Mast)null); ShipyardUI instance = ShipyardUI.instance; if ((Object)(object)instance != (Object)null) { instance.ChangeMenuCategory(-1); instance.CloseSailCategoryMenu(); instance.HideNewSailButtons(); } } private static bool HasUnconfirmedShipyardOrder(Shipyard shipyard) { if (shipyard.IncludeHullCleaning() || shipyard.IncludeRepair()) { return true; } List<ShipyardRefund> currentRefunds = shipyard.GetCurrentRefunds(); if (currentRefunds != null && currentRefunds.Count > 0) { return true; } GameObject currentBoat = shipyard.GetCurrentBoat(); BoatRefs component = currentBoat.GetComponent<BoatRefs>(); if ((((Object)(object)component != (Object)null) ? component.masts : null) != null) { Mast[] masts = component.masts; foreach (Mast val in masts) { if ((Object)(object)val == (Object)null || val.sails == null) { continue; } foreach (GameObject sail in val.sails) { Sail val2 = (((Object)(object)sail != (Object)null) ? sail.GetComponent<Sail>() : null); if ((Object)(object)val2 != (Object)null && !val2.IsInstalled()) { return true; } } } } BoatCustomParts component2 = currentBoat.GetComponent<BoatCustomParts>(); BoatPartsOrder val3 = (((Object)(object)shipyard.partsInstaller != (Object)null) ? shipyard.partsInstaller.GetCurrentOrder() : null); if ((((Object)(object)component2 != (Object)null) ? component2.availableParts : null) != null && val3?.orderedOptions != null) { int num = Math.Min(component2.availableParts.Count, val3.orderedOptions.Length); for (int j = 0; j < num; j++) { if (component2.availableParts[j].activeOption != val3.orderedOptions[j]) { return true; } } } return false; } private static bool HasSupportedStay(GameObject boat) { BoatRefs component = boat.GetComponent<BoatRefs>(); if ((((Object)(object)component != (Object)null) ? component.masts : null) != null) { return component.masts.Any((Mast mast) => (Object)(object)mast != (Object)null && ((Component)mast).gameObject.activeInHierarchy && StaysailTargets.IsEligible(mast)); } return false; } internal static bool IsAllowedMast(Mast mast) { if (Active) { return StaysailTargets.IsEligible(mast); } return false; } internal static bool IsAllowedSailPrefab(GameObject prefab) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Invalid comparison between Unknown and I4 Sail val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Sail>() : null); if ((Object)(object)val != (Object)null) { return (int)val.category == 5; } return false; } internal static IReadOnlyList<SailmakerPreview> GetPreviews() { Previews.RemoveAll((SailmakerPreview preview) => preview == null || (Object)(object)preview.Mast == (Object)null || (Object)(object)preview.Sail == (Object)null); return Previews; } internal static List<SailmakerPreview> GetPreviews(Mast mast) { return (from preview in GetPreviews() where (Object)(object)preview.Mast == (Object)(object)mast select preview).ToList(); } internal static bool IsPreview(Sail sail) { if ((Object)(object)sail != (Object)null) { return GetPreviews().Any((SailmakerPreview preview) => (Object)(object)preview.Sail == (Object)(object)sail); } return false; } internal static bool AddPreview(GameObject prefab) { if (!Active || !IsAllowedSailPrefab(prefab)) { return false; } Mast currentMast = ActiveShipyard.sailInstaller.GetCurrentMast(); if (!IsAllowedMast(currentMast)) { Notify("Select a supported staysail stay."); return false; } GameObject[] obj = (((Object)(object)ShipyardUI.instance != (Object)null) ? (SelectSailButtonsField?.GetValue(ShipyardUI.instance) as GameObject[]) : null); int num = ((obj != null) ? obj.Length : 0); if (GetPreviews(currentMast).Count >= num) { Notify((num > 0) ? $"Order at most {num} staysails per stay.\nBuy or remove one first." : "The staysail selection menu is unavailable."); return false; } GameObject val = null; try { val = Object.Instantiate<GameObject>(prefab); Sail component = val.GetComponent<Sail>(); SailConnections component2 = val.GetComponent<SailConnections>(); if (!CanSupplyPreviewControllers(currentMast, component2)) { Object.Destroy((Object)(object)val); Notify("That stay does not have the required sail controllers."); return false; } EnsurePreviewRigCapacity(currentMast, (currentMast.sails?.Count ?? 0) + 1); ActiveShipyard.sailInstaller.AddNewSail(val); Previews.Add(new SailmakerPreview(currentMast, component)); ActiveShipyard.sailInstaller.RecheckAllSailsCols(); RefreshPreviewUi(); ManualLogSource log = SwappableStaysailPlugin.Log; if (log != null) { log.LogInfo((object)("Added registered Sail Maker preview '" + component.sailName + "' for " + StaysailTargets.GetStayName(currentMast) + ".")); } return true; } catch (Exception arg) { if ((Object)(object)val != (Object)null) { if (currentMast.sails != null && currentMast.sails.Contains(val)) { currentMast.DetachSailFromMast(val); } else { Object.Destroy((Object)(object)val); } } RestorePreviewRigIfUnused(currentMast); ManualLogSource log2 = SwappableStaysailPlugin.Log; if (log2 != null) { log2.LogError((object)$"Could not add Sail Maker preview: {arg}"); } Notify("Could not add that staysail."); return false; } } internal static bool SelectPreview(int index) { if (!Active) { return false; } List<SailmakerPreview> previews = GetPreviews(ActiveShipyard.sailInstaller.GetCurrentMast()); if (index < 0 || index >= previews.Count) { return