Decompiled source of Propeller v1.0.0

BepInEx/plugins/Propeller/Propeller.dll

Decompiled 14 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Crest;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[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("Propeller")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Propeller")]
[assembly: AssemblyTitle("Propeller")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace JetPump
{
	[BepInPlugin("DogEggz.JetPump", "Propeller", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "DogEggz.JetPump";

		internal static ManualLogSource Log;

		internal static bool Ready;

		private static ConfigEntry<float> waterOffset;

		private static ConfigEntry<float> trimAngle;

		private Harmony harmony;

		internal static float WaterOffset => Finite(waterOffset, 0f, -0.2f, 0.2f);

		internal static float TrimAngle => Finite(trimAngle, 80f, 0f, 180f);

		private static float Finite(ConfigEntry<float> entry, float fallback, float min, float max)
		{
			float num = entry?.Value ?? fallback;
			if (!float.IsNaN(num) && !float.IsInfinity(num))
			{
				return Mathf.Clamp(num, min, max);
			}
			return fallback;
		}

		internal static void BindSettings(ConfigFile config)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			waterOffset = config.Bind<float>("Water", "Contact offset (metres)", 0f, new ConfigDescription("Small contact calibration only. Positive activates slightly earlier; negative requires deeper immersion.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.2f, 0.2f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					ShowRangeAsPercent = false
				}
			}));
			trimAngle = config.Bind<float>("Trim", "Bow-up angle (degrees)", 80f, new ConfigDescription("Average bow-up target during forward propulsion, shared by all propellers on a boat. Zero targets level with pitch compensation, 90 vertical and 180 inverted. Values above 90 permit intentional inversion.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 180f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					ShowRangeAsPercent = false
				}
			}));
		}

		private void Awake()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			BindSettings(((BaseUnityPlugin)this).Config);
			try
			{
				PumpAssets.Load(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location));
				harmony = new Harmony("DogEggz.JetPump");
				harmony.PatchAll(typeof(Plugin).Assembly);
				PumpInput.PatchCheatspeed(harmony);
				((Component)this).gameObject.AddComponent<PairingMenu>();
				Ready = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Propeller 1.0.0 loaded: Propeller 604 (30,000 N), controller 605, Huge Propeller 606 (600,000 N).");
			}
			catch (Exception ex)
			{
				Ready = false;
				Harmony obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
				PumpAssets.Unload();
				((BaseUnityPlugin)this).Logger.LogError((object)("Propeller initialization aborted: " + ex));
			}
		}

		private void OnDestroy()
		{
			Ready = false;
			PairingMenu.Close();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			PumpWorld.Reset();
			PumpAssets.Unload();
		}
	}
	internal static class PumpAssets
	{
		internal const string BundleName = "dogeggz.jetpump.assets";

		internal static AssetBundle Bundle;

		internal static GameObject Pump;

		internal static GameObject Controller;

		internal static GameObject HugePump;

		internal static void Load(string folder)
		{
			string text = Path.Combine(folder, "assets", "dogeggz.jetpump.assets");
			Bundle = AssetBundle.LoadFromFile(text);
			if (!Object.op_Implicit((Object)(object)Bundle))
			{
				throw new FileNotFoundException("Propeller AssetBundle could not be loaded", text);
			}
			Pump = Bundle.LoadAsset<GameObject>("Assets/JetPump/Generated/604 propeller.prefab");
			Controller = Bundle.LoadAsset<GameObject>("Assets/JetPump/Generated/605 Pump Controller.prefab");
			HugePump = Bundle.LoadAsset<GameObject>("Assets/JetPump/Generated/606 Huge Propeller.prefab");
			Validate(HugePump, 606);
			Validate(Pump, 604);
			Validate(Controller, 605);
		}

		private static void Validate(GameObject prefab, int id)
		{
			if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent<ShipItem>()) || !Object.op_Implicit((Object)(object)prefab.GetComponent<SaveablePrefab>()) || prefab.GetComponent<SaveablePrefab>().prefabIndex != id || !prefab.GetComponent<ShipItem>().wallAttachment || !Object.op_Implicit((Object)(object)prefab.transform.Find("JetPumpAssetContract_v12")))
			{
				throw new InvalidOperationException("Invalid bundled item " + id);
			}
		}

		internal static bool IsOurItem(ShipItem item)
		{
			SaveablePrefab component = ((Component)item).GetComponent<SaveablePrefab>();
			if (Object.op_Implicit((Object)(object)component) && PumpState.IsItem(component.prefabIndex))
			{
				return Object.op_Implicit((Object)(object)((Component)item).transform.Find("JetPumpAssetContract_v12"));
			}
			return false;
		}

		internal static void Register(PrefabsDirectory directory)
		{
			GameObject[] array = directory.directory;
			if (array == null)
			{
				throw new InvalidOperationException("Missing prefab directory");
			}
			int[] array2 = new int[3] { 604, 605, 606 };
			for (int i = 0; i < array2.Length; i++)
			{
				int num = array2[i];
				GameObject val = (GameObject)(num switch
				{
					605 => Controller, 
					604 => Pump, 
					_ => HugePump, 
				});
				if (num < array.Length && Object.op_Implicit((Object)(object)array[num]) && (Object)(object)array[num] != (Object)(object)val)
				{
					throw new InvalidOperationException("Propeller refuses occupied prefab " + num + " (" + ((Object)array[num]).name + ").");
				}
			}
			if (array.Length <= 606)
			{
				Array.Resize(ref array, 607);
			}
			array[604] = Pump;
			array[605] = Controller;
			array[606] = HugePump;
			directory.directory = array;
		}

		internal static void Unload()
		{
			if (Object.op_Implicit((Object)(object)Bundle))
			{
				Bundle.Unload(false);
			}
			Bundle = null;
			Pump = (Controller = (HugePump = null));
		}
	}
	[HarmonyPatch(typeof(PrefabsDirectory), "Start")]
	internal static class RegisterPumpPrefabs
	{
		private static void Prefix(PrefabsDirectory __instance)
		{
			try
			{
				PumpAssets.Register(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Ready = false;
				Plugin.Log.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(ShipItem), "Awake")]
	internal static class AddPumpRuntime
	{
		private static void Prefix(ShipItem __instance)
		{
			if (Plugin.Ready && PumpAssets.IsOurItem(__instance) && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<PumpItem>()))
			{
				((Component)__instance).gameObject.AddComponent<PumpItem>();
			}
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public bool? ShowRangeAsPercent;
	}
	internal static class PumpWorld
	{
		internal const string SaveKey = "DogEggz.JetPump.v1";

		internal static PumpState State = new PumpState();

		internal static int Session;

		internal static bool Loading;

		internal static readonly List<PumpItem> Live = new List<PumpItem>();

		internal static bool SimulationAllowed
		{
			get
			{
				if (Plugin.Ready && !Loading && State.Writable && GameState.playing && !GameState.currentlyLoading && !GameState.loadingBoatLocalItems && !GameState.justStarted && !GameState.recovering && !Object.op_Implicit((Object)(object)GameState.currentShipyard))
				{
					return Time.timeScale > 0f;
				}
				return false;
			}
		}

		internal static bool InputAllowed
		{
			get
			{
				if (SimulationAllowed && !GameState.sleeping && !Object.op_Implicit((Object)(object)GameState.inBed) && !GameState.inCursorMenu && !GameState.wasInSettingsMenu && !BoatCamera.on)
				{
					return !PairingMenu.IsOpen;
				}
				return false;
			}
		}

		internal static void Reset()
		{
			PairingMenu.Close();
			PumpTrim.ResetAll();
			PumpMount.ResetCache();
			State = new PumpState();
			Session++;
			Loading = false;
		}

		internal static void Load()
		{
			bool loading = Loading;
			string value = null;
			GameState.modData?.TryGetValue("DogEggz.JetPump.v1", out value);
			State = PumpState.Decode(value);
			if (loading && State.Writable)
			{
				ReconcileSavedNumbers();
			}
			Session++;
			Loading = false;
			if (!State.Writable)
			{
				Plugin.Log.LogError((object)"JetPump save data is unsupported or invalid. Original data retained; propulsion disabled for this session.");
			}
		}

		internal static void ReconcileSavedNumbers()
		{
			SaveLoadManager instance = SaveLoadManager.instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return;
			}
			List<SaveablePrefab> currentPrefabs = instance.GetCurrentPrefabs();
			SaveableObject[] array = AccessTools.Field(typeof(SaveLoadManager), "currentObjects").GetValue(instance) as SaveableObject[];
			if (currentPrefabs == null || array == null)
			{
				return;
			}
			HashSet<int> hashSet = new HashSet<int>();
			foreach (SaveablePrefab item in currentPrefabs)
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					hashSet.Add(item.instanceId);
				}
			}
			SaveableObject[] array2 = array;
			foreach (SaveableObject val in array2)
			{
				if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.localItems))
				{
					continue;
				}
				List<SavePrefabData> cachedItems = val.localItems.GetCachedItems();
				if (cachedItems == null)
				{
					continue;
				}
				foreach (SavePrefabData item2 in cachedItems)
				{
					hashSet.Add(item2.instanceId);
				}
			}
			State.RetainSavedItems(hashSet);
		}

		internal static void Save()
		{
			if (!State.Writable || Loading)
			{
				return;
			}
			foreach (PumpItem item in Live)
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					item.EnforceNails();
					item.Mount.CapturePose();
				}
			}
			if (GameState.modData == null)
			{
				GameState.modData = new Dictionary<string, string>();
			}
			GameState.modData["DogEggz.JetPump.v1"] = State.Encode();
		}

		internal static PumpItem Find(int id)
		{
			for (int i = 0; i < Live.Count; i++)
			{
				if (Object.op_Implicit((Object)(object)Live[i]) && !Live[i].Retiring && !Live[i].Mount.Cached && ((Behaviour)Live[i]).isActiveAndEnabled && Object.op_Implicit((Object)(object)Live[i].Saveable) && Live[i].Saveable.instanceId == id)
				{
					return Live[i];
				}
			}
			return null;
		}

		internal static void RetireDuplicate(PumpItem incoming, int id)
		{
			if (id <= 0)
			{
				return;
			}
			for (int num = Live.Count - 1; num >= 0; num--)
			{
				PumpItem pumpItem = Live[num];
				if (Object.op_Implicit((Object)(object)pumpItem) && !((Object)(object)pumpItem == (Object)(object)incoming) && !pumpItem.Retiring && Object.op_Implicit((Object)(object)pumpItem.Saveable) && pumpItem.Saveable.instanceId == id && pumpItem.Saveable.prefabIndex == incoming.Saveable.prefabIndex)
				{
					pumpItem.Retiring = true;
					pumpItem.Item.DestroyItem();
				}
			}
		}

		internal static int BoatId(Transform actualBoat)
		{
			SaveableObject val = (Object.op_Implicit((Object)(object)actualBoat) ? ((Component)actualBoat).GetComponentInParent<SaveableObject>() : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return 0;
			}
			return val.sceneIndex;
		}

		internal static bool PairOperational(PumpItem box, out PumpItem pump)
		{
			pump = null;
			if (!Object.op_Implicit((Object)(object)box))
			{
				return false;
			}
			box.EnforceNails();
			if (!box.CanOperate || !State.ValidPair(box.Record))
			{
				return false;
			}
			pump = Find(box.Record.PeerId);
			if (Object.op_Implicit((Object)(object)pump))
			{
				pump.EnforceNails();
			}
			if (Object.op_Implicit((Object)(object)pump) && pump.Installed && pump.Item.nailed)
			{
				return (Object)(object)pump.Item.currentActualBoat == (Object)(object)box.Item.currentActualBoat;
			}
			return false;
		}

		internal static void AutoPair(PumpItem box)
		{
			if (!Object.op_Implicit((Object)(object)box) || !box.CanOperate || box.Record.PeerId != 0 || box.Record.RequirePairChoice)
			{
				return;
			}
			PumpItem pumpItem = null;
			foreach (PumpItem item in Live)
			{
				if (Object.op_Implicit((Object)(object)item) && item.IsPump && item.Installed && item.Record.PeerId == 0 && !item.Record.RequirePairChoice && !((Object)(object)item.Item.currentActualBoat != (Object)(object)box.Item.currentActualBoat))
				{
					if (Object.op_Implicit((Object)(object)pumpItem))
					{
						return;
					}
					pumpItem = item;
				}
			}
			if (Object.op_Implicit((Object)(object)pumpItem))
			{
				State.Pair(box.Record.Id, pumpItem.Record.Id, box.Record.BoatId);
			}
		}

		internal static string WheelKey(GPButtonSteeringWheel wheel, Transform boatRoot)
		{
			if (!Object.op_Implicit((Object)(object)wheel) || !Object.op_Implicit((Object)(object)boatRoot) || !((Component)wheel).transform.IsChildOf(boatRoot))
			{
				return "";
			}
			List<string> list = new List<string>();
			Transform val = ((Component)wheel).transform;
			while (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)boatRoot)
			{
				list.Add(((Object)val).name + "#" + val.GetSiblingIndex());
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list.ToArray());
		}

		internal static GPButtonSteeringWheel FindWheel(PumpItem box)
		{
			Transform val = (Object.op_Implicit((Object)(object)box.Item.currentActualBoat) ? box.Item.currentActualBoat.parent : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			GPButtonSteeringWheel[] componentsInChildren = ((Component)val).GetComponentsInChildren<GPButtonSteeringWheel>(false);
			GPButtonSteeringWheel val2 = null;
			GPButtonSteeringWheel[] array = componentsInChildren;
			foreach (GPButtonSteeringWheel val3 in array)
			{
				if (((GoPointerButton)val3).IsStickyClicked() || ((GoPointerButton)val3).IsCliked())
				{
					return val3;
				}
				if (!Object.op_Implicit((Object)(object)val2))
				{
					val2 = val3;
					continue;
				}
				return null;
			}
			return val2;
		}

		internal static PumpItem Selected(GPButtonSteeringWheel wheel)
		{
			foreach (PumpItem item in Live)
			{
				if (Object.op_Implicit((Object)(object)item) && item.CanOperate && !string.IsNullOrEmpty(item.Record.Wheel) && (Object)(object)item.BoundWheel == (Object)(object)wheel && PairOperational(item, out var _))
				{
					return item;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(SaveLoadManager), "Awake")]
	internal static class PumpSessionStart
	{
		private static void Prefix()
		{
			PumpWorld.Reset();
		}
	}
	[HarmonyPatch(typeof(SaveLoadManager), "LoadGame")]
	internal static class PumpBeginLoad
	{
		private static void Prefix()
		{
			PumpWorld.Reset();
			PumpWorld.Loading = true;
			GameState.modData?.Remove("DogEggz.JetPump.v1");
		}
	}
	[HarmonyPatch(typeof(SaveLoadManager), "LoadModData")]
	internal static class PumpLoad
	{
		private static void Postfix()
		{
			PumpWorld.Load();
		}
	}
	[HarmonyPatch(typeof(SaveLoadManager), "SaveModData")]
	internal static class PumpSave
	{
		private static void Prefix()
		{
			PumpWorld.Save();
		}
	}
	public sealed class PumpRecord
	{
		public int Id;

		public int Kind;

		public int PeerId;

		public int BoatId;

		public bool Mounted;

		public int Power = 5;

		public float Throttle;

		public bool Enabled;

		public bool RequireImmersion;

		public bool RequirePairChoice;

		public int Number;

		public string Wheel = "";

		public bool HasPose;

		public float X;

		public float Y;

		public float Z;

		public float Qx;

		public float Qy;

		public float Qz;

		public float Qw = 1f;

		public float AppliedPower
		{
			get
			{
				if (!Enabled)
				{
					return 0f;
				}
				return (float)Power * Throttle;
			}
		}

		public void Normalize()
		{
			Power = Math.Max(5, Math.Min(100, (int)Math.Round((double)Power / 5.0) * 5));
			Throttle = ((float.IsNaN(Throttle) || float.IsInfinity(Throttle)) ? 0f : Math.Max(0f, Math.Min(1f, Throttle)));
			if (PeerId < 0)
			{
				PeerId = 0;
			}
			if (BoatId <= 0)
			{
				BoatId = 0;
				Mounted = false;
			}
			Wheel = Wheel ?? "";
			if (!Mounted)
			{
				Enabled = false;
				Wheel = "";
			}
			if (!Mounted || !Finite(X) || !Finite(Y) || !Finite(Z) || !Finite(Qx) || !Finite(Qy) || !Finite(Qz) || !Finite(Qw) || Qx * Qx + Qy * Qy + Qz * Qz + Qw * Qw < 0.01f)
			{
				HasPose = false;
			}
		}

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

		public void ChangePower(int direction)
		{
			Power = Math.Max(5, Math.Min(100, Power + Math.Sign(direction) * 5));
		}

		public void AdjustThrottle(bool forward, bool decrease, float seconds)
		{
			if (forward != decrease && !(seconds <= 0f) && !float.IsNaN(seconds) && !float.IsInfinity(seconds))
			{
				Throttle = Math.Max(0f, Math.Min(1f, Throttle + (forward ? 1f : (-1f)) * seconds * 0.2f));
			}
		}

		public void StopForRemoval()
		{
			Enabled = false;
			Mounted = false;
			Wheel = "";
			HasPose = false;
		}
	}
	public sealed class PumpState
	{
		public const int PumpId = 604;

		public const int ControllerId = 605;

		public const int HugePumpId = 606;

		public readonly Dictionary<int, PumpRecord> Items = new Dictionary<int, PumpRecord>();

		public bool Writable = true;

		public bool MigratedNumbers;

		private static readonly CultureInfo Invariant = CultureInfo.InvariantCulture;

		public static bool IsPump(int kind)
		{
			if (kind != 604)
			{
				return kind == 606;
			}
			return true;
		}

		public static bool IsItem(int kind)
		{
			if (!IsPump(kind))
			{
				return kind == 605;
			}
			return true;
		}

		public static float RatedThrust(int kind)
		{
			return kind switch
			{
				604 => 30000f, 
				606 => 600000f, 
				_ => 0f, 
			};
		}

		public static string Label(PumpRecord pump)
		{
			return ((pump.Kind == 606) ? "H.PROP " : "PROP ") + pump.Number.ToString("00");
		}

		public PumpRecord GetOrCreate(int id, int kind)
		{
			if (id <= 0 || !IsItem(kind))
			{
				throw new ArgumentException("Invalid item identity.");
			}
			if (!Items.TryGetValue(id, out var value))
			{
				Dictionary<int, PumpRecord> items = Items;
				PumpRecord obj = new PumpRecord
				{
					Id = id,
					Kind = kind
				};
				value = obj;
				items.Add(id, obj);
			}
			if (value.Kind != kind)
			{
				throw new InvalidOperationException("Saved item identity belongs to a different prefab.");
			}
			return value;
		}

		public PumpRecord Peer(PumpRecord item)
		{
			if (item != null && Items.TryGetValue(item.PeerId, out var value) && value.PeerId == item.Id && ((item.Kind == 605 && IsPump(value.Kind)) || (value.Kind == 605 && IsPump(item.Kind))))
			{
				return value;
			}
			return null;
		}

		public bool Pair(int controllerId, int pumpId, int boatId)
		{
			if (!Items.TryGetValue(controllerId, out var value) || !Items.TryGetValue(pumpId, out var value2) || value.Kind != 605 || !IsPump(value2.Kind) || boatId <= 0 || !value.Mounted || !value2.Mounted || value.BoatId != boatId || value2.BoatId != boatId)
			{
				return false;
			}
			if (value2.PeerId != 0 && value2.PeerId != controllerId)
			{
				PumpRecord pumpRecord = Peer(value2);
				if (pumpRecord != null && pumpRecord.Mounted)
				{
					return false;
				}
				if (pumpRecord != null)
				{
					pumpRecord.PeerId = 0;
					pumpRecord.Wheel = "";
					pumpRecord.RequirePairChoice = true;
				}
			}
			PumpRecord pumpRecord2 = Peer(value);
			if (pumpRecord2 != null && pumpRecord2 != value2)
			{
				pumpRecord2.PeerId = 0;
				pumpRecord2.Enabled = false;
			}
			value.PeerId = value2.Id;
			value2.PeerId = value.Id;
			value.Wheel = "";
			value.RequirePairChoice = false;
			value2.RequirePairChoice = false;
			value2.Enabled = false;
			value2.Throttle = 0f;
			return true;
		}

		public bool ValidPair(PumpRecord box)
		{
			PumpRecord pumpRecord = Peer(box);
			if (box != null && box.Kind == 605 && pumpRecord != null && box.Mounted && pumpRecord.Mounted && box.BoatId > 0)
			{
				return pumpRecord.BoatId == box.BoatId;
			}
			return false;
		}

		public void RemoveFromWall(PumpRecord item)
		{
			item.StopForRemoval();
			PumpRecord pumpRecord = Peer(item);
			if (pumpRecord != null)
			{
				pumpRecord.Enabled = false;
				pumpRecord.Wheel = "";
			}
		}

		public void StopController(PumpRecord box)
		{
			if (box != null && box.Kind == 605)
			{
				box.Wheel = "";
				PumpRecord pumpRecord = Peer(box);
				if (pumpRecord != null)
				{
					pumpRecord.Enabled = false;
				}
			}
		}

		public void StopPump(PumpRecord pump)
		{
			if (pump != null && IsPump(pump.Kind))
			{
				pump.Enabled = false;
				PumpRecord pumpRecord = Peer(pump);
				if (pumpRecord != null)
				{
					pumpRecord.Wheel = "";
				}
			}
		}

		public void Install(PumpRecord item, int boatId)
		{
			if (boatId <= 0)
			{
				return;
			}
			if (item.BoatId != 0 && item.BoatId != boatId)
			{
				PumpRecord pumpRecord = Peer(item);
				if (pumpRecord != null)
				{
					pumpRecord.PeerId = 0;
					pumpRecord.Enabled = false;
					pumpRecord.Wheel = "";
					pumpRecord.RequirePairChoice = true;
				}
				item.PeerId = 0;
				item.RequirePairChoice = true;
				item.Enabled = false;
				item.Throttle = 0f;
				item.Wheel = "";
				item.HasPose = false;
				item.Number = 0;
			}
			item.BoatId = boatId;
			item.Mounted = true;
			if (IsPump(item.Kind) && item.Number == 0)
			{
				item.Number = AvailableNumber(boatId);
			}
		}

		private int AvailableNumber(int boatId)
		{
			HashSet<int> hashSet = new HashSet<int>();
			foreach (PumpRecord value in Items.Values)
			{
				if (IsPump(value.Kind) && value.BoatId == boatId && value.Number > 0)
				{
					hashSet.Add(value.Number);
				}
			}
			int i;
			for (i = 1; hashSet.Contains(i); i++)
			{
			}
			return i;
		}

		public void Forget(int id)
		{
			if (Items.TryGetValue(id, out var value))
			{
				PumpRecord pumpRecord = Peer(value);
				if (pumpRecord != null)
				{
					pumpRecord.PeerId = 0;
					pumpRecord.Enabled = false;
					pumpRecord.Wheel = "";
					pumpRecord.RequirePairChoice = true;
				}
				Items.Remove(id);
			}
		}

		public void RetainSavedItems(HashSet<int> savedIds)
		{
			if (!Writable || savedIds == null)
			{
				return;
			}
			foreach (int item in new List<int>(Items.Keys))
			{
				if (!savedIds.Contains(item))
				{
					Forget(item);
				}
			}
			if (MigratedNumbers)
			{
				RebuildNumbers();
			}
		}

		private void RebuildNumbers()
		{
			List<PumpRecord> list = new List<PumpRecord>();
			foreach (PumpRecord value2 in Items.Values)
			{
				if (IsPump(value2.Kind))
				{
					list.Add(value2);
				}
			}
			list.Sort((PumpRecord a, PumpRecord b) => (a.Number == b.Number) ? a.Id.CompareTo(b.Id) : a.Number.CompareTo(b.Number));
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			foreach (PumpRecord item in list)
			{
				if (item.BoatId <= 0)
				{
					item.Number = 0;
					continue;
				}
				dictionary.TryGetValue(item.BoatId, out var value);
				item.Number = value + 1;
				dictionary[item.BoatId] = item.Number;
			}
		}

		public bool Select(PumpRecord box, string wheel)
		{
			if (!ValidPair(box) || string.IsNullOrEmpty(wheel))
			{
				return false;
			}
			foreach (PumpRecord value in Items.Values)
			{
				if (value.Kind == 605 && value.BoatId == box.BoatId && value.Wheel == wheel)
				{
					value.Wheel = "";
				}
			}
			box.Wheel = wheel;
			return true;
		}

		public string Encode()
		{
			StringBuilder stringBuilder = new StringBuilder("JetPump/5\n");
			List<int> list = new List<int>(Items.Keys);
			list.Sort();
			foreach (int item in list)
			{
				PumpRecord pumpRecord = Items[item];
				stringBuilder.Append(pumpRecord.Id).Append('|').Append(pumpRecord.Kind)
					.Append('|')
					.Append(pumpRecord.PeerId)
					.Append('|')
					.Append(pumpRecord.BoatId)
					.Append('|')
					.Append(pumpRecord.Mounted ? 1 : 0)
					.Append('|')
					.Append(pumpRecord.Power)
					.Append('|')
					.Append(pumpRecord.Throttle.ToString("R", Invariant))
					.Append('|')
					.Append(pumpRecord.Enabled ? 1 : 0)
					.Append('|')
					.Append(Convert.ToBase64String(Encoding.UTF8.GetBytes(pumpRecord.Wheel ?? "")))
					.Append('|')
					.Append(pumpRecord.RequirePairChoice ? 1 : 0)
					.Append('|')
					.Append(pumpRecord.Number)
					.Append('|')
					.Append(pumpRecord.HasPose ? 1 : 0);
				float[] array = new float[7] { pumpRecord.X, pumpRecord.Y, pumpRecord.Z, pumpRecord.Qx, pumpRecord.Qy, pumpRecord.Qz, pumpRecord.Qw };
				foreach (float num in array)
				{
					stringBuilder.Append('|').Append(num.ToString("R", Invariant));
				}
				stringBuilder.Append('|').Append(pumpRecord.RequireImmersion ? 1 : 0);
				stringBuilder.Append('\n');
			}
			return stringBuilder.ToString();
		}

		public static PumpState Decode(string encoded)
		{
			PumpState pumpState = new PumpState();
			if (string.IsNullOrEmpty(encoded))
			{
				return pumpState;
			}
			string[] array = encoded.Split(new char[1] { '\n' });
			bool flag = array[0].TrimEnd(new char[1] { '\r' }) == "JetPump/1";
			bool flag2 = array[0].TrimEnd(new char[1] { '\r' }) == "JetPump/2";
			bool flag3 = array[0].TrimEnd(new char[1] { '\r' }) == "JetPump/3";
			bool flag4 = array[0].TrimEnd(new char[1] { '\r' }) == "JetPump/4" || array[0].TrimEnd(new char[1] { '\r' }) == "JetPump/5";
			if (!flag && !flag2 && !flag3 && !flag4)
			{
				pumpState.Writable = false;
				return pumpState;
			}
			pumpState.MigratedNumbers = flag || flag2;
			try
			{
				for (int i = 1; i < array.Length; i++)
				{
					if (string.IsNullOrWhiteSpace(array[i]))
					{
						continue;
					}
					string[] array2 = array[i].TrimEnd(new char[1] { '\r' }).Split(new char[1] { '|' });
					if (array2.Length != (flag ? 11 : (flag4 ? 20 : 19)))
					{
						throw new FormatException("Record length");
					}
					PumpRecord pumpRecord = new PumpRecord
					{
						Id = int.Parse(array2[0], Invariant),
						Kind = int.Parse(array2[1], Invariant),
						PeerId = int.Parse(array2[2], Invariant),
						BoatId = int.Parse(array2[3], Invariant),
						Mounted = (array2[4] == "1"),
						Power = int.Parse(array2[5], Invariant),
						Throttle = float.Parse(array2[6], Invariant),
						Enabled = (array2[7] == "1"),
						Wheel = Encoding.UTF8.GetString(Convert.FromBase64String(array2[8])),
						RequirePairChoice = (array2[9] == "1"),
						Number = int.Parse(array2[10], Invariant)
					};
					if (!flag)
					{
						pumpRecord.HasPose = array2[11] == "1";
						pumpRecord.X = float.Parse(array2[12], Invariant);
						pumpRecord.Y = float.Parse(array2[13], Invariant);
						pumpRecord.Z = float.Parse(array2[14], Invariant);
						pumpRecord.Qx = float.Parse(array2[15], Invariant);
						pumpRecord.Qy = float.Parse(array2[16], Invariant);
						pumpRecord.Qz = float.Parse(array2[17], Invariant);
						pumpRecord.Qw = float.Parse(array2[18], Invariant);
					}
					if (flag4)
					{
						if (array2[19] != "0" && array2[19] != "1")
						{
							throw new FormatException("Immersion switch");
						}
						pumpRecord.RequireImmersion = array2[19] == "1";
					}
					if (pumpRecord.Id <= 0 || !IsItem(pumpRecord.Kind) || pumpState.Items.ContainsKey(pumpRecord.Id))
					{
						throw new FormatException("Record identity");
					}
					pumpRecord.Normalize();
					if (IsPump(pumpRecord.Kind) && (pumpRecord.Number < 0 || (pumpRecord.BoatId > 0 && pumpRecord.Number == 0)))
					{
						throw new FormatException("Pump label");
					}
					pumpState.Items.Add(pumpRecord.Id, pumpRecord);
				}
				if (pumpState.MigratedNumbers)
				{
					pumpState.RebuildNumbers();
				}
				HashSet<string> hashSet = new HashSet<string>();
				foreach (PumpRecord value2 in pumpState.Items.Values)
				{
					if (IsPump(value2.Kind) && value2.BoatId > 0 && !hashSet.Add(value2.BoatId + ":" + value2.Number))
					{
						throw new FormatException("Duplicate boat label");
					}
				}
				Dictionary<string, PumpRecord> dictionary = new Dictionary<string, PumpRecord>();
				foreach (PumpRecord value3 in pumpState.Items.Values)
				{
					PumpRecord pumpRecord2 = pumpState.Peer(value3);
					if (pumpRecord2 == null || !pumpRecord2.Mounted || !value3.Mounted || pumpRecord2.BoatId != value3.BoatId)
					{
						value3.Enabled = false;
						value3.Wheel = "";
					}
					if (value3.Wheel.Length != 0)
					{
						string key = value3.BoatId + ":" + value3.Wheel;
						if (dictionary.TryGetValue(key, out var value))
						{
							value.Wheel = "";
							value3.Wheel = "";
						}
						else
						{
							dictionary.Add(key, value3);
						}
					}
				}
			}
			catch (Exception)
			{
				pumpState.Items.Clear();
				pumpState.Writable = false;
			}
			return pumpState;
		}
	}
	public sealed class PumpItem : MonoBehaviour
	{
		internal ShipItem Item;

		internal SaveablePrefab Saveable;

		internal PumpRecord Record;

		internal PumpMount Mount;

		internal PumpWater Water;

		internal bool Retiring;

		private int session = -1;

		private int warmup;

		private float reconcileTimer;

		private Transform rotor;

		private Transform needle;

		private Transform lever;

		private Transform immersionLever;

		private Vector3 thrustLocal;

		private Vector3 thrustFacing;

		private Vector3 rotorAxis;

		private Vector3 needleAxis;

		private Quaternion leverBase;

		private Quaternion immersionBase;

		private Quaternion needleBase;

		private TextMesh[] powerDigits;

		private TextMesh identityText;

		private PumpPowerDisplay powerDisplay;

		private readonly PumpDrive drive = new PumpDrive();

		private readonly List<PumpControl> controls = new List<PumpControl>();

		private Rigidbody boatBody;

		private PumpTrim trim;

		private Transform bodyOwner;

		private string cachedWheelKey;

		private Transform cachedWheelBoat;

		private GPButtonSteeringWheel cachedWheel;

		internal bool IsPump
		{
			get
			{
				if (Object.op_Implicit((Object)(object)Saveable))
				{
					return PumpState.IsPump(Saveable.prefabIndex);
				}
				return false;
			}
		}

		internal bool Installed
		{
			get
			{
				if (!Retiring && !Mount.Cached && Record != null && Record.Mounted && warmup >= 8 && Item.sold && !Object.op_Implicit((Object)(object)((PickupableItem)Item).held) && Object.op_Implicit((Object)(object)Item.currentActualBoat) && PumpWorld.BoatId(Item.currentActualBoat) == Record.BoatId && Object.op_Implicit((Object)(object)Item.itemRigidbodyC) && Item.itemRigidbodyC.attached && Mount.Verified && (Object)(object)Item.itemRigidbodyC.GetCurrentInventorySlot() == (Object)null && (Object)(object)Item.itemRigidbodyC.GetCurrentBox() == (Object)null && Saveable.currentCrateId == 0)
				{
					return ((Component)this).gameObject.layer != 26;
				}
				return false;
			}
		}

		internal bool CanOperate
		{
			get
			{
				if (!IsPump && Installed)
				{
					return Item.nailed;
				}
				return false;
			}
		}

		internal bool WheelSelected
		{
			get
			{
				if (CanOperate && Object.op_Implicit((Object)(object)BoundWheel))
				{
					return (Object)(object)PumpWorld.Selected(BoundWheel) == (Object)(object)this;
				}
				return false;
			}
		}

		internal GPButtonSteeringWheel BoundWheel
		{
			get
			{
				if (Record == null || !Object.op_Implicit((Object)(object)Item.currentActualBoat) || string.IsNullOrEmpty(Record.Wheel))
				{
					return null;
				}
				if (cachedWheelKey != Record.Wheel || (Object)(object)cachedWheelBoat != (Object)(object)Item.currentActualBoat || !Object.op_Implicit((Object)(object)cachedWheel))
				{
					cachedWheelKey = Record.Wheel;
					cachedWheelBoat = Item.currentActualBoat;
					cachedWheel = null;
					GPButtonSteeringWheel[] componentsInChildren = ((Component)Item.currentActualBoat.parent).GetComponentsInChildren<GPButtonSteeringWheel>(false);
					foreach (GPButtonSteeringWheel wheel in componentsInChildren)
					{
						if (PumpWorld.WheelKey(wheel, Item.currentActualBoat.parent) == Record.Wheel)
						{
							cachedWheel = wheel;
							break;
						}
					}
				}
				return cachedWheel;
			}
		}

		private void Awake()
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			Item = ((Component)this).GetComponent<ShipItem>();
			Saveable = ((Component)this).GetComponent<SaveablePrefab>();
			Mount = new PumpMount(this);
			Vector3 val2;
			if (IsPump)
			{
				Transform val = Require("ThrustPoint");
				thrustLocal = ((Component)this).transform.InverseTransformPoint(val.position);
				val2 = ((Component)this).transform.InverseTransformDirection(val.forward);
				thrustFacing = ((Vector3)(ref val2)).normalized;
				rotor = Require("RotorPivot");
				val2 = rotor.InverseTransformDirection(val.forward);
				rotorAxis = ((Vector3)(ref val2)).normalized;
				Water = new PumpWater(this, Require("WaterOpening"));
			}
			else
			{
				needle = Require("ThrottleNeedlePivot");
				lever = Require("OnOffLeverPivot");
				needleBase = needle.localRotation;
				val2 = needle.parent.InverseTransformDirection(((Component)this).transform.forward);
				needleAxis = ((Vector3)(ref val2)).normalized;
				leverBase = lever.localRotation;
				powerDigits = (TextMesh[])(object)new TextMesh[3]
				{
					((Component)Require("PowerTextHundreds")).GetComponent<TextMesh>(),
					((Component)Require("PowerTextTens")).GetComponent<TextMesh>(),
					((Component)Require("PowerTextOnes")).GetComponent<TextMesh>()
				};
				powerDisplay = new PumpPowerDisplay(((Component)this).transform, powerDigits);
				AddControl("HIT_OnOff", PumpControl.Action.Toggle, null);
				AddControl("HIT_PowerDecrease", PumpControl.Action.Decrease, Require("PowerDecreasePivot"));
				AddControl("HIT_PowerIncrease", PumpControl.Action.Increase, Require("PowerIncreasePivot"));
				AddControl("HIT_WheelAssign", PumpControl.Action.SelectWheel, Require("WheelAssignPivot"));
				immersionLever = Require("ImmersionLeverPivot");
				immersionBase = immersionLever.localRotation;
				AddControl("HIT_Immersion", PumpControl.Action.Immersion, null);
			}
			identityText = ((Component)Require("IdentityText")).GetComponent<TextMesh>();
		}

		private Transform Require(string name)
		{
			Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name == name)
				{
					return val;
				}
			}
			throw new InvalidOperationException("Propeller asset missing " + name);
		}

		private void AddControl(string name, PumpControl.Action action, Transform button)
		{
			PumpControl pumpControl = ((Component)Require(name)).gameObject.AddComponent<PumpControl>();
			pumpControl.Configure(this, action, button);
			controls.Add(pumpControl);
		}

		private void OnEnable()
		{
			if (!PumpWorld.Live.Contains(this))
			{
				PumpWorld.Live.Add(this);
			}
			Font.textureRebuilt += RefreshFont;
			RefreshFont(Object.op_Implicit((Object)(object)identityText) ? identityText.font : null);
		}

		private void OnDisable()
		{
			StopDrive(resetWater: true);
			powerDisplay?.Reset();
			PumpWorld.Live.Remove(this);
			Font.textureRebuilt -= RefreshFont;
		}

		internal void StopDrive(bool resetWater = false)
		{
			drive.Stop();
			if (resetWater)
			{
				Water?.Reset();
			}
		}

		private void RefreshFont(Font font)
		{
			if (Object.op_Implicit((Object)(object)font) && Object.op_Implicit((Object)(object)identityText) && (Object)(object)identityText.font == (Object)(object)font)
			{
				((Component)identityText).GetComponent<Renderer>().sharedMaterial.mainTexture = font.material.mainTexture;
			}
			if (!Object.op_Implicit((Object)(object)font) || powerDigits == null)
			{
				return;
			}
			TextMesh[] array = powerDigits;
			foreach (TextMesh val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && (Object)(object)val.font == (Object)(object)font)
				{
					((Component)val).GetComponent<Renderer>().sharedMaterial.mainTexture = font.material.mainTexture;
				}
			}
		}

		internal bool EnsureState()
		{
			if (Retiring || PumpWorld.Loading || !PumpWorld.State.Writable || !Object.op_Implicit((Object)(object)Saveable) || Saveable.instanceId <= 0)
			{
				return false;
			}
			if (session != PumpWorld.Session || Record == null || Record.Id != Saveable.instanceId)
			{
				Record = PumpWorld.State.GetOrCreate(Saveable.instanceId, Saveable.prefabIndex);
				session = PumpWorld.Session;
				warmup = 0;
				Mount.ResetBinding();
				StopDrive(resetWater: true);
				powerDisplay?.Reset();
			}
			return true;
		}

		internal void Removed()
		{
			Mount.Cancel();
			StopDrive(resetWater: true);
			if (EnsureState())
			{
				PumpWorld.State.RemoveFromWall(Record);
			}
		}

		internal void EnforceNails()
		{
			if (!Retiring && !Mount.Cached && !PumpWorld.Loading && !GameState.currentlyLoading && Record != null && !Item.nailed)
			{
				if (IsPump)
				{
					PumpWorld.State.StopPump(Record);
				}
				else
				{
					PumpWorld.State.StopController(Record);
				}
				StopDrive(resetWater: true);
			}
		}

		private void Update()
		{
			if (!EnsureState())
			{
				StopDrive(resetWater: true);
				powerDisplay?.Reset();
				SetControls(active: false);
				return;
			}
			EnforceNails();
			if (IsPump)
			{
				if (Installed && Item.nailed && PumpWorld.SimulationAllowed)
				{
					if (Record.RequireImmersion)
					{
						Water.Sample();
					}
					else
					{
						Water.Reset();
					}
				}
				else
				{
					StopDrive(resetWater: true);
				}
				if (!Record.Enabled)
				{
					StopDrive();
				}
			}
			SetControls(CanOperate && PumpWorld.SimulationAllowed);
			reconcileTimer -= Time.deltaTime;
			if (reconcileTimer <= 0f && PumpWorld.SimulationAllowed)
			{
				reconcileTimer = 0.25f;
				if (CanOperate)
				{
					PumpWorld.AutoPair(this);
				}
				if (!Installed && warmup >= 8 && Record.Mounted && (Object.op_Implicit((Object)(object)((PickupableItem)Item).held) || Mount.Stored))
				{
					Removed();
				}
			}
			RefreshView();
		}

		private void SetControls(bool active)
		{
			for (int i = 0; i < controls.Count; i++)
			{
				controls[i].SetAvailable(active);
			}
		}

		private void FixedUpdate()
		{
			if (!ApplyThrust())
			{
				StopDrive();
			}
		}

		private bool ApplyThrust()
		{
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			if (!EnsureState() || !Object.op_Implicit((Object)(object)Item.itemRigidbodyC))
			{
				return false;
			}
			EnforceNails();
			if (!PumpWorld.SimulationAllowed)
			{
				return false;
			}
			Mount.Tick();
			if (Mount.Pending)
			{
				return false;
			}
			if (warmup < 8)
			{
				Item.itemRigidbodyC.attached = Record.Mounted && !Object.op_Implicit((Object)(object)((PickupableItem)Item).held) && Saveable.currentCrateId == 0;
				warmup++;
				return false;
			}
			if (!IsPump || !Installed || !Item.nailed || Record.AppliedPower <= 0f)
			{
				return false;
			}
			if (!PumpWorld.PairOperational(PumpWorld.Find(Record.PeerId), out var pump) || (Object)(object)pump != (Object)(object)this)
			{
				return false;
			}
			if ((Object)(object)bodyOwner != (Object)(object)Item.currentActualBoat || !Object.op_Implicit((Object)(object)boatBody))
			{
				bodyOwner = Item.currentActualBoat;
				boatBody = (Object.op_Implicit((Object)(object)bodyOwner.parent) ? ((Component)bodyOwner.parent).GetComponent<Rigidbody>() : null);
				trim = null;
			}
			if (!Object.op_Implicit((Object)(object)boatBody) || boatBody.isKinematic || !Object.op_Implicit((Object)(object)Item.currentWalkCol) || (Object)(object)((Component)Item.itemRigidbodyC).transform.parent != (Object)(object)Item.currentWalkCol)
			{
				return false;
			}
			if (Record.RequireImmersion)
			{
				Water.Evaluate();
			}
			float num = Water.Power(Record);
			if (num <= 0f)
			{
				return false;
			}
			Vector3 point = ((Component)Item.itemRigidbodyC).transform.TransformPoint(thrustLocal);
			Vector3 direction = ((Component)Item.itemRigidbodyC).transform.TransformDirection(thrustFacing);
			Vector3 point2 = ConvertPoint(point, Item.currentWalkCol, Item.currentActualBoat);
			Vector3 val = ConvertDirection(direction, Item.currentWalkCol, Item.currentActualBoat);
			if (!Object.op_Implicit((Object)(object)trim))
			{
				trim = ((Component)boatBody).GetComponent<PumpTrim>() ?? ((Component)boatBody).gameObject.AddComponent<PumpTrim>();
			}
			drive.Apply(boatBody, -val, point2, num, Time.fixedDeltaTime, trim, PumpState.RatedThrust(Record.Kind));
			return true;
		}

		public static Vector3 ConvertPoint(Vector3 point, Transform walk, Transform actual)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: 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)
			return actual.TransformPoint(walk.InverseTransformPoint(point));
		}

		public static Vector3 ConvertDirection(Vector3 direction, Transform walk, Transform actual)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: 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_000d: 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)
			Vector3 val = actual.TransformDirection(walk.InverseTransformDirection(direction));
			return ((Vector3)(ref val)).normalized;
		}

		private void RefreshView()
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			PumpRecord pumpRecord = (IsPump ? Record : PumpWorld.State.Peer(Record));
			string text = ((pumpRecord == null || pumpRecord.Number <= 0) ? "UNPAIRED" : PumpState.Label(pumpRecord));
			if (Object.op_Implicit((Object)(object)identityText) && identityText.text != text)
			{
				identityText.text = text;
			}
			if (IsPump)
			{
				if (Installed && Item.nailed && PumpWorld.SimulationAllowed && Record.Enabled && PumpWorld.PairOperational(PumpWorld.Find(Record.PeerId), out var _))
				{
					rotor.Rotate(rotorAxis, 720f * Record.Throttle * Time.deltaTime, (Space)1);
				}
				return;
			}
			float num = pumpRecord?.Throttle ?? 0f;
			needle.localRotation = Quaternion.AngleAxis(Mathf.Lerp(80f, -80f, Mathf.Clamp01(num)), needleAxis) * needleBase;
			int next = pumpRecord?.Power ?? (-1);
			powerDisplay.Show(next, Time.deltaTime, !PumpWorld.InputAllowed);
			lever.localRotation = leverBase * Quaternion.AngleAxis((pumpRecord != null && pumpRecord.Enabled) ? (-50f) : 50f, Vector3.right);
			immersionLever.localRotation = immersionBase * Quaternion.AngleAxis((pumpRecord != null && pumpRecord.RequireImmersion) ? (-35f) : 35f, Vector3.right);
		}
	}
	public sealed class PumpControl : GoPointerButton
	{
		internal enum Action
		{
			Toggle,
			Decrease,
			Increase,
			SelectWheel,
			Immersion
		}

		internal PumpItem Owner;

		private Action action;

		private Transform button;

		private Vector3 rest;

		private Vector3 pressDirection;

		private Quaternion restRotation;

		private Vector3 rockerAxis;

		private GameObject ivory;

		private Collider hitCollider;

		private float pressUntil;

		internal bool CanUse
		{
			get
			{
				if (Object.op_Implicit((Object)(object)Owner) && Owner.CanOperate)
				{
					return PumpWorld.InputAllowed;
				}
				return false;
			}
		}

		internal void Configure(PumpItem owner, Action kind, Transform animatedButton)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			Owner = owner;
			action = kind;
			button = animatedButton;
			hitCollider = ((Component)this).GetComponent<Collider>();
			hitCollider.enabled = false;
			Vector3 val;
			if (Object.op_Implicit((Object)(object)button))
			{
				rest = button.localPosition;
				val = button.parent.InverseTransformDirection(((Component)owner).transform.forward);
				pressDirection = ((Vector3)(ref val)).normalized * 0.00363f;
			}
			if (kind == Action.SelectWheel)
			{
				restRotation = button.localRotation;
				val = button.parent.InverseTransformDirection(((Component)owner).transform.up);
				rockerAxis = ((Vector3)(ref val)).normalized;
				Transform[] componentsInChildren = ((Component)button).GetComponentsInChildren<Transform>(true);
				foreach (Transform val2 in componentsInChildren)
				{
					if (((Object)val2).name == "WheelIvoryStrip")
					{
						ivory = ((Component)val2).gameObject;
					}
				}
				if (!Object.op_Implicit((Object)(object)ivory))
				{
					throw new InvalidOperationException("Missing left-edge wheel indicator");
				}
			}
			base.description = (base.lookText = "");
			base.enableRedOutline = false;
		}

		internal void SetAvailable(bool available)
		{
			if (available)
			{
				((Component)this).gameObject.layer = 0;
			}
			if (Object.op_Implicit((Object)(object)hitCollider))
			{
				hitCollider.enabled = available;
			}
			base.unclickable = !available;
		}

		public override void OnActivate(GoPointer pointer)
		{
			if (!Object.op_Implicit((Object)(object)pointer) || !(pointer.GetHeldItem() is ShipItemHammer))
			{
				Activate();
			}
		}

		public override void OnAltActivate(GoPointer pointer)
		{
			if ((!Object.op_Implicit((Object)(object)pointer) || !(pointer.GetHeldItem() is ShipItemHammer)) && CanUse && action == Action.SelectWheel)
			{
				PairingMenu.Open(Owner);
			}
		}

		internal void Activate()
		{
			if (!CanUse)
			{
				return;
			}
			PumpRecord pumpRecord = PumpWorld.State.Peer(Owner.Record);
			if (pumpRecord == null)
			{
				if (Owner.Record.PeerId == 0)
				{
					PairingMenu.Open(Owner);
				}
				else
				{
					Notify("Paired propeller is not ready.");
				}
				return;
			}
			PumpItem pump = PumpWorld.Find(pumpRecord.Id);
			if (Object.op_Implicit((Object)(object)pump) && !pump.Item.nailed)
			{
				Notify("Propeller is not hammered.\nNail it down before use.");
				return;
			}
			if (!PumpWorld.PairOperational(Owner, out pump))
			{
				Notify("Paired propeller is not ready.");
				return;
			}
			switch (action)
			{
			case Action.Toggle:
				pump.Record.Enabled = !pump.Record.Enabled;
				if (!pump.Record.Enabled)
				{
					pump.StopDrive();
				}
				break;
			case Action.Immersion:
				pump.Record.RequireImmersion = !pump.Record.RequireImmersion;
				break;
			case Action.Decrease:
				pump.Record.ChangePower(-1);
				break;
			case Action.Increase:
				pump.Record.ChangePower(1);
				break;
			case Action.SelectWheel:
			{
				GPButtonSteeringWheel val = PumpWorld.FindWheel(Owner);
				if (Object.op_Implicit((Object)(object)val))
				{
					PumpWorld.State.Select(Owner.Record, PumpWorld.WheelKey(val, Owner.Item.currentActualBoat.parent));
				}
				break;
			}
			}
			pressUntil = Time.time + 0.14f;
		}

		private static void Notify(string message)
		{
			if (Object.op_Implicit((Object)(object)NotificationUi.instance))
			{
				NotificationUi.instance.ShowNotification(message);
			}
		}

		public override void ExtraLateUpdate()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)button))
			{
				bool flag = ((action != Action.SelectWheel) ? (Time.time < pressUntil) : (Object.op_Implicit((Object)(object)Owner) && Owner.WheelSelected));
				if (action == Action.SelectWheel)
				{
					button.localRotation = Quaternion.AngleAxis(flag ? (-10f) : 10f, rockerAxis) * restRotation;
					ivory.SetActive(flag);
				}
				else
				{
					button.localPosition = rest + (flag ? pressDirection : Vector3.zero);
				}
			}
		}
	}
	internal sealed class PumpMount
	{
		private static readonly MethodInfo EnterBoat = AccessTools.Method(typeof(ShipItem), "EnterBoat", (Type[])null, (Type[])null);

		private static readonly MethodInfo Targeter = AccessTools.Method(typeof(ShipItem), "SetUpTargeter", (Type[])null, (Type[])null);

		private static readonly FieldInfo ItemSave = AccessTools.Field(typeof(ShipItem), "saveable");

		private static readonly FieldInfo TargeterActive = AccessTools.Field(typeof(GoPointerTargeter), "targeterActive");

		private static BoatEmbarkCollider[] boats;

		private static float nextBoatScan;

		private static readonly RaycastHit[] hits = (RaycastHit[])(object)new RaycastHit[64];

		private readonly PumpItem owner;

		private readonly BoxCollider housing;

		private Collider contact;

		private Vector3 contactPosition;

		private Quaternion contactRotation;

		private bool previewValid;

		private bool recoveryChecked;

		private BoatEmbarkCollider bound;

		internal bool Pending;

		internal bool LoadedFromSave;

		internal bool Stored
		{
			get
			{
				if (owner.Saveable.currentCrateId == 0 && ((Component)owner).gameObject.layer != 26)
				{
					if (Object.op_Implicit((Object)(object)owner.Item.itemRigidbodyC))
					{
						if (!Object.op_Implicit((Object)(object)owner.Item.itemRigidbodyC.GetCurrentBox()))
						{
							return Object.op_Implicit((Object)(object)owner.Item.itemRigidbodyC.GetCurrentInventorySlot());
						}
						return true;
					}
					return false;
				}
				return true;
			}
		}

		internal bool Cached
		{
			get
			{
				if (Object.op_Implicit((Object)(object)owner.Saveable))
				{
					if (owner.Saveable.GetParentObject() != -2)
					{
						return owner.Saveable.GetParentObject() == -3;
					}
					return true;
				}
				return false;
			}
		}

		internal bool ProtectOwnership
		{
			get
			{
				if (!Cached)
				{
					if (!Object.op_Implicit((Object)(object)((PickupableItem)owner.Item).held) && !Stored)
					{
						if (!Pending)
						{
							if (owner.Record != null)
							{
								return owner.Record.Mounted;
							}
							return false;
						}
						return true;
					}
					return false;
				}
				return true;
			}
		}

		internal bool Verified
		{
			get
			{
				if (Object.op_Implicit((Object)(object)bound) && (Object)(object)owner.Item.currentActualBoat == (Object)(object)((Component)bound).transform.parent && (Object)(object)owner.Item.currentWalkCol == (Object)(object)bound.walkCollider && (Object)(object)((Component)owner.Item).transform.parent == (Object)(object)((Component)bound).transform.parent && Object.op_Implicit((Object)(object)owner.Item.itemRigidbodyC) && (Object)(object)((Component)owner.Item.itemRigidbodyC).transform.parent == (Object)(object)bound.walkCollider)
				{
					return owner.Saveable.GetParentObject() == PumpWorld.BoatId(((Component)bound).transform.parent);
				}
				return false;
			}
		}

		internal PumpMount(PumpItem owner)
		{
			this.owner = owner;
			housing = ((Component)owner).GetComponent<BoxCollider>();
		}

		internal static void ResetCache()
		{
			boats = null;
			nextBoatScan = 0f;
		}

		internal void ResetBinding()
		{
			bound = null;
			recoveryChecked = false;
		}

		internal void Cancel()
		{
			Pending = (previewValid = false);
			contact = null;
			bound = null;
			LoadedFromSave = false;
		}

		private static BoatEmbarkCollider[] Boats()
		{
			if (boats == null || Time.unscaledTime >= nextBoatScan)
			{
				boats = Object.FindObjectsOfType<BoatEmbarkCollider>();
				nextBoatScan = Time.unscaledTime + 2f;
			}
			return boats;
		}

		private static bool Usable(BoatEmbarkCollider boat)
		{
			if (!Object.op_Implicit((Object)(object)boat) || !Object.op_Implicit((Object)(object)boat.walkCollider) || !Object.op_Implicit((Object)(object)((Component)boat).transform.parent) || !Object.op_Implicit((Object)(object)((Component)boat).transform.parent.parent) || !Object.op_Implicit((Object)(object)((Component)boat).GetComponent<Collider>()))
			{
				return false;
			}
			Transform parent = ((Component)boat).transform.parent.parent;
			if (Object.op_Implicit((Object)(object)((Component)parent).GetComponent<Rigidbody>()) && Object.op_Implicit((Object)(object)((Component)parent).GetComponent<BoatMass>()))
			{
				return PumpWorld.BoatId(((Component)boat).transform.parent) > 0;
			}
			return false;
		}

		internal static BoatEmbarkCollider ResolveSurface(Collider surface, out Transform frame)
		{
			frame = null;
			if (!Object.op_Implicit((Object)(object)surface) || Object.op_Implicit((Object)(object)((Component)surface).GetComponentInParent<ShipItem>()) || Object.op_Implicit((Object)(object)((Component)surface).GetComponentInParent<ItemRigidbody>()))
			{
				return null;
			}
			BoatEmbarkCollider val = null;
			BoatEmbarkCollider[] array = Boats();
			foreach (BoatEmbarkCollider val2 in array)
			{
				if (!Usable(val2))
				{
					continue;
				}
				Transform val3 = (((Component)surface).transform.IsChildOf(val2.walkCollider) ? val2.walkCollider : (((Component)surface).transform.IsChildOf(((Component)val2).transform.parent.parent) ? ((Component)val2).transform.parent : null));
				if (Object.op_Implicit((Object)(object)val3))
				{
					if (Object.op_Implicit((Object)(object)val) && (Object)(object)((Component)val).transform.parent != (Object)(object)((Component)val2).transform.parent)
					{
						frame = null;
						return null;
					}
					val = val2;
					frame = val3;
				}
			}
			return val;
		}

		private static BoatEmbarkCollider FindSavedBoat(int id)
		{
			if (id <= 0)
			{
				return null;
			}
			BoatEmbarkCollider[] array = Boats();
			foreach (BoatEmbarkCollider val in array)
			{
				if (Usable(val) && PumpWorld.BoatId(((Component)val).transform.parent) == id)
				{
					return val;
				}
			}
			return null;
		}

		private bool Raycast(Ray ray, float distance, out RaycastHit hit)
		{
			//IL_0000: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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)
			int num = Physics.RaycastNonAlloc(ray, hits, distance, -5, (QueryTriggerInteraction)1);
			RaycastHit[] array = ((num == hits.Length) ? Physics.RaycastAll(ray, distance, -5, (QueryTriggerInteraction)1) : hits);
			if (array != hits)
			{
				num = array.Length;
			}
			hit = default(RaycastHit);
			float num2 = float.PositiveInfinity;
			for (int i = 0; i < num; i++)
			{
				Collider collider = ((RaycastHit)(ref array[i])).collider;
				if (Object.op_Implicit((Object)(object)collider) && !((Component)collider).transform.IsChildOf(((Component)owner).transform) && (!Object.op_Implicit((Object)(object)owner.Item.itemRigidbodyC) || !((Component)collider).transform.IsChildOf(((Component)owner.Item.itemRigidbodyC).transform)) && ((RaycastHit)(ref array[i])).distance < num2)
				{
					num2 = ((RaycastHit)(ref array[i])).distance;
					hit = array[i];
				}
			}
			return Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).collider);
		}

		internal static Quaternion SurfaceRotation(Vector3 normal, Vector3 itemUp)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.ProjectOnPlane((normal.y > 0.8f) ? itemUp : Vector3.up, normal);
			if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
			{
				val = Vector3.ProjectOnPlane(itemUp, normal);
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
			{
				val = Vector3.ProjectOnPlane(Vector3.forward, normal);
			}
			return Quaternion.LookRotation(-normal, ((Vector3)(ref val)).normalized);
		}

		internal bool Preview(Transform proxy, out Vector3 position, out Quaternion rotation)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			previewValid = false;
			position = Vector3.zero;
			rotation = Quaternion.identity;
			if (!Object.op_Implicit((Object)(object)proxy) || !Object.op_Implicit((Object)(object)((PickupableItem)owner.Item).held) || !PumpWorld.InputAllowed)
			{
				return false;
			}
			if (!Raycast(new Ray(proxy.position, proxy.forward), 1.3f, out var hit) || ((RaycastHit)(ref hit)).distance < 0.1f)
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)ResolveSurface(((RaycastHit)(ref hit)).collider, out var _)))
			{
				return false;
			}
			rotation = SurfaceRotation(((RaycastHit)(ref hit)).normal, ((Component)owner).transform.up);
			position = ClearancePosition(((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).normal, rotation);
			RememberContact(((RaycastHit)(ref hit)).collider, position, rotation);
			return true;
		}

		internal Vector3 ClearancePosition(Vector3 point, Vector3 normal, Quaternion rotation)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			if (Object.op_Implicit((Object)(object)housing))
			{
				Vector3 val = housing.size * 0.5f;
				for (int i = -1; i <= 1; i += 2)
				{
					for (int j = -1; j <= 1; j += 2)
					{
						for (int k = -1; k <= 1; k += 2)
						{
							num = Mathf.Min(num, Vector3.Dot(rotation * (housing.center + Vector3.Scale(val, new Vector3((float)i, (float)j, (float)k))), normal));
						}
					}
				}
			}
			return point + normal * (0.001f - num);
		}

		internal void RememberContact(Collider surface, Vector3 position, Quaternion rotation)
		{
			//IL_000e: 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_0014: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			contact = surface;
			contactPosition = ((Component)surface).transform.InverseTransformPoint(position);
			contactRotation = Quaternion.Inverse(((Component)surface).transform.rotation) * rotation;
			previewValid = true;
		}

		internal void Drop(bool attached)
		{
			Pending = attached && previewValid && Object.op_Implicit((Object)(object)contact);
			bound = null;
		}

		internal void Tick()
		{
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			if (Cached || owner.Retiring || Object.op_Implicit((Object)(object)((PickupableItem)owner.Item).held) || Stored || !owner.Item.sold || !Object.op_Implicit((Object)(object)owner.Item.itemRigidbodyC) || !Object.op_Implicit((Object)(object)owner.Item.itemRigidbodyC.GetBody()) || ItemSave.GetValue(owner.Item) == null)
			{
				return;
			}
			if (Pending)
			{
				if (!Object.op_Implicit((Object)(object)contact))
				{
					Pending = false;
					return;
				}
				Transform frame;
				BoatEmbarkCollider val = ResolveSurface(contact, out frame);
				if (Object.op_Implicit((Object)(object)val))
				{
					Vector3 local = frame.InverseTransformPoint(((Component)contact).transform.TransformPoint(contactPosition));
					Quaternion localRot = Quaternion.Inverse(frame.rotation) * ((Component)contact).transform.rotation * contactRotation;
					if (Bind(val, local, localRot))
					{
						PumpWorld.State.Install(owner.Record, PumpWorld.BoatId(((Component)val).transform.parent));
						CapturePose();
						Pending = false;
					}
				}
			}
			else if (owner.Record.Mounted && !Verified)
			{
				int parentObject = owner.Saveable.GetParentObject();
				if (parentObject > 0 && parentObject != owner.Record.BoatId)
				{
					return;
				}
				BoatEmbarkCollider val2 = FindSavedBoat(owner.Record.BoatId);
				PumpRecord record = owner.Record;
				if (Object.op_Implicit((Object)(object)val2))
				{
					? local2 = (record.HasPose ? new Vector3(record.X, record.Y, record.Z) : ((Component)val2).transform.parent.InverseTransformPoint(((Component)owner).transform.position));
					Quaternion localRot2;
					if (!record.HasPose)
					{
						localRot2 = Quaternion.Inverse(((Component)val2).transform.parent.rotation) * ((Component)owner).transform.rotation;
					}
					else
					{
						Quaternion val3 = new Quaternion(record.Qx, record.Qy, record.Qz, record.Qw);
						localRot2 = ((Quaternion)(ref val3)).normalized;
					}
					if (Bind(val2, (Vector3)local2, localRot2))
					{
						CapturePose();
					}
				}
			}
			else
			{
				if (owner.Record.Mounted || !LoadedFromSave || recoveryChecked)
				{
					return;
				}
				recoveryChecked = true;
				Vector3 forward = ((Component)owner).transform.forward;
				if (Raycast(new Ray(((Component)owner).transform.position - forward * 0.05f, forward), 0.07f, out var hit) && !(Vector3.Distance(((RaycastHit)(ref hit)).point, ((Component)owner).transform.position) > 0.012f) && !(Vector3.Dot(-((RaycastHit)(ref hit)).normal, forward) < 0.985f))
				{
					Transform frame2;
					BoatEmbarkCollider val4 = ResolveSurface(((RaycastHit)(ref hit)).collider, out frame2);
					if (Object.op_Implicit((Object)(object)val4) && (owner.Saveable.GetParentObject() <= 0 || owner.Saveable.GetParentObject() == PumpWorld.BoatId(((Component)val4).transform.parent)) && !((Object)(object)frame2 != (Object)(object)((Component)val4).transform.parent) && Bind(val4, frame2.InverseTransformPoint(((Component)owner).transform.position), Quaternion.Inverse(frame2.rotation) * ((Component)owner).transform.rotation))
					{
						PumpWorld.State.Install(owner.Record, PumpWorld.BoatId(((Component)val4).transform.parent));
						CapturePose();
					}
				}
			}
		}

		internal void CapturePose()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			if (!Cached && !owner.Retiring && Verified && owner.Record != null && owner.Record.Mounted && !Object.op_Implicit((Object)(object)((PickupableItem)owner.Item).held) && !Stored)
			{
				Transform currentActualBoat = owner.Item.currentActualBoat;
				Vector3 val = currentActualBoat.InverseTransformPoint(((Component)owner).transform.position);
				Quaternion val2 = Quaternion.Inverse(currentActualBoat.rotation) * ((Component)owner).transform.rotation;
				PumpRecord record = owner.Record;
				record.X = val.x;
				record.Y = val.y;
				record.Z = val.z;
				record.Qx = val2.x;
				record.Qy = val2.y;
				record.Qz = val2.z;
				record.Qw = val2.w;
				record.HasPose = true;
			}
		}

		private bool Bind(BoatEmbarkCollider boat, Vector3 local, Quaternion localRot)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			ShipItem item = owner.Item;
			ItemRigidbody itemRigidbodyC = item.itemRigidbodyC;
			if (!Usable(boat) || !Object.op_Implicit((Object)(object)itemRigidbodyC) || !Object.op_Implicit((Object)(object)itemRigidbodyC.GetBody()) || ItemSave.GetValue(item) == null)
			{
				return false;
			}
			if (Object.op_Implicit((Object)(object)item.currentActualBoat) && (Object)(object)item.currentActualBoat != (Object)(object)((Component)boat).transform.parent)
			{
				itemRigidbodyC.ExitBoat();
			}
			((Component)item).transform.position = ((Component)boat).transform.parent.TransformPoint(local);
			((Component)item).transform.rotation = ((Component)boat).transform.parent.rotation * localRot;
			EnterBoat.Invoke(item, new object[1] { ((Component)boat).GetComponent<Collider>() });
			itemRigidbodyC.attached = true;
			itemRigidbodyC.GetBody().velocity = Vector3.zero;
			itemRigidbodyC.GetBody().angularVelocity = Vector3.zero;
			itemRigidbodyC.GetBody().isKinematic = true;
			bound = boat;
			return Verified;
		}

		internal void ShowPreview(Vector3 position, Quaternion rotation)
		{
			//IL_0018: 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)
			Targeter.Invoke(owner.Item, new object[3]
			{
				position,
				rotation,
				((Component)owner).GetComponent<MeshFilter>().sharedMesh
			});
		}

		internal void HidePreview()
		{
			GoPointerTargeter targeter = ((PickupableItem)owner.Item).held.GetTargeter();
			if (Object.op_Implicit((Object)(object)targeter))
			{
				TargeterActive.SetValue(targeter, false);
			}
		}
	}
	[HarmonyPatch(typeof(ShipItem), "Update")]
	internal static class PumpPlacementPreview
	{
		[HarmonyPriority(0)]
		private static void Postfix(ShipItem __instance, Transform ___itemRigidbody, ref bool ___inRangeOfWall, ref Vector3 ___attachPos, ref Quaternion ___attachRot)
		{
			//IL_0039: 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)
			PumpItem component = ((Component)__instance).GetComponent<PumpItem>();
			if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)((PickupableItem)__instance).held))
			{
				___inRangeOfWall = component.Mount.Preview(___itemRigidbody, out ___attachPos, out ___attachRot);
				if (___inRangeOfWall)
				{
					component.Mount.ShowPreview(___attachPos, ___attachRot);
				}
				else
				{
					component.Mount.HidePreview();
				}
			}
		}
	}
	[HarmonyPatch(typeof(ShipItem), "ExtraFixedUpdate")]
	internal static class PumpKeepMountedBoat
	{
		private static bool Prefix(ShipItem __instance)
		{
			PumpItem component = ((Component)__instance).GetComponent<PumpItem>();
			if (Object.op_Implicit((Object)(object)component))
			{
				return !component.Mount.ProtectOwnership;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(SaveablePrefab), "Load")]
	internal static class PumpLoadedPlacement
	{
		private static void Prefix(SaveablePrefab __instance, SavePrefabData data, bool ___loaded)
		{
			PumpItem component = ((Component)__instance).GetComponent<PumpItem>();
			if (Object.op_Implicit((Object)(object)component) && !___loaded)
			{
				PumpWorld.RetireDuplicate(component, data.instanceId);
			}
		}

		private static void Postfix(SaveablePrefab __instance)
		{
			PumpItem component = ((Component)__instance).GetComponent<PumpItem>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.Mount.LoadedFromSave = true;
				component.Mount.ResetBinding();
				PumpMount.ResetCache();
			}
		}
	}
	[HarmonyPatch(typeof(SaveablePrefab), "PrepareSaveData")]
	internal static class PumpSavePose
	{
		private static void Prefix(SaveablePrefab __instance)
		{
			((Component)__instance).GetComponent<PumpItem>()?.Mount.CapturePose();
		}
	}
	[HarmonyPatch(typeof(GoPointer), "MainButtonDown")]
	internal static class PumpClickWhileSteering
	{
		private static int activatedFrame = -1;

		private static void Postfix(GoPointer __instance, GoPointerButton ___stickyClickedButton, GoPointerButton ___pointedAtButton, ref bool __result)
		{
			if (!__result || __instance.GetHeldItem() is ShipItemHammer)
			{
				return;
			}
			GPButtonSteeringWheel val = (GPButtonSteeringWheel)(object)((___stickyClickedButton is GPButtonSteeringWheel) ? ___stickyClickedButton : null);
			if (val == null)
			{
				return;
			}
			PumpControl pumpControl = ___pointedAtButton as PumpControl;
			if (Object.op_Implicit((Object)(object)pumpControl) && pumpControl.CanUse && ((Component)val).transform.IsChildOf(pumpControl.Owner.Item.currentActualBoat.parent))
			{
				if (activatedFrame != Time.frameCount)
				{
					activatedFrame = Time.frameCount;
					pumpControl.Activate();
				}
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(GoPointer), "GetPointedAtItem")]
	internal static class PumpHammerTarget
	{
		private static void Postfix(GoPointer __instance, GoPointerButton ___pointedAtButton, ref ShipItem __result)
		{
			if (__instance.GetHeldItem() is ShipItemHammer && ___pointedAtButton is PumpControl pumpControl && Object.op_Implicit((Object)(object)pumpControl.Owner))
			{
				__result = pumpControl.Owner.Item;
			}
		}
	}
	[HarmonyPatch(typeof(ShipItemHammer), "AllowOnItemClick")]
	internal static class PumpHammerAllowed
	{
		private static bool Prefix(GoPointerButton lookedAtButton, ref bool __result)
		{
			if (!(lookedAtButton is PumpControl pumpControl) || !Object.op_Implicit((Object)(object)pumpControl.Owner))
			{
				return true;
			}
			__result = ShipItemHammer.CanNail(pumpControl.Owner.Item);
			return false;
		}
	}
	[HarmonyPatch(typeof(ShipItemHammer), "NailItem")]
	internal static class PumpHammerMovingMount
	{
		private static bool Prefix(ShipItem item)
		{
			PumpItem pumpItem = (Object.op_Implicit((Object)(object)item) ? ((Component)item).GetComponent<PumpItem>() : null);
			if (!Object.op_Implicit((Object)(object)pumpItem))
			{
				return true;
			}
			if (PumpWorld.InputAllowed && pumpItem.Installed)
			{
				item.nailed = true;
				if (Object.op_Implicit((Object)(object)UISoundPlayer.instance))
				{
					UISoundPlayer.instance.PlayUISound((UISounds)11, 1f, 0.6f);
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ShipItem), "OnPickup")]
	internal static class PumpPickup
	{
		private static void Prefix(ShipItem __instance)
		{
			((Component)__instance).GetComponent<PumpItem>()?.Removed();
		}
	}
	[HarmonyPatch(typeof(ShipItem), "OnDrop")]
	internal static class PumpDrop
	{
		private static void Postfix(ShipItem __instance, bool ___inRangeOfWall)
		{
			PumpItem component = ((Component)__instance).GetComponent<PumpItem>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.Mount.Drop(__instance.sold && ___inRangeOfWall && !((GoPointerButton)__instance).forceDisableRedOutline && Object.op_Implicit((Object)(object)__instance.itemRigidbodyC) && __instance.itemRigidbodyC.attached);
			}
		}
	}
	[HarmonyPatch(typeof(ShipItem), "OnEnterInventory")]
	internal static class PumpInventory
	{
		private static void Prefix(ShipItem __instance)
		{
			((Component)__instance).GetComponent<PumpItem>()?.Removed();
		}
	}
	[HarmonyPatch(typeof(ShipItem), "DestroyItem")]
	internal static class PumpDestroy
	{
		private static void Prefix(ShipItem __instance)
		{
			PumpItem component = ((Component)__instance).GetComponent<PumpItem>();
			if (Object.op_Implicit((Object)(object)component))
			{
				if (!component.Retiring && !component.Mount.Cached && !PumpWorld.Loading && !GameState.currentlyLoading && component.EnsureState())
				{
					component.Removed();
					PumpWorld.State.Forget(component.Saveable.instanceId);
				}
				component.Retiring = true;
			}
		}
	}
	internal sealed class PumpPowerDisplay
	{
		private static readonly string[] Labels = new string[11]
		{
			"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
			"-"
		};

		private readonly TextMesh[] digits;

		private readonly Transform[] pivots = (Transform[])(object)new Transform[3];

		private readonly Quaternion[] restRotation = (Quaternion[])(object)new Quaternion[3];

		private readonly Vector3[] restPosition = (Vector3[])(object)new Vector3[3];

		private readonly Vector3[] axis = (Vector3[])(object)new Vector3[3];

		private readonly Vector3[] outward = (Vector3[])(object)new Vector3[3];

		private readonly int[] shown = new int[3];

		private readonly int[] target = new int[3];

		private readonly float[] elapsed = new float[3] { 0.25f, 0.25f, 0.25f };

		private readonly float[] direction = new float[3];

		private int value = int.MinValue;

		internal PumpPowerDisplay(Transform panel, TextMesh[] texts)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			digits = texts;
			for (int i = 0; i < 3; i++)
			{
				pivots[i] = ((Component)texts[i]).transform.parent.parent;
				restRotation[i] = pivots[i].localRotation;
				restPosition[i] = pivots[i].localPosition;
				Vector3[] array = axis;
				int num = i;
				Vector3 val = pivots[i].parent.InverseTransformDirection(panel.right);
				array[num] = ((Vector3)(ref val)).normalized;
				Vector3[] array2 = outward;
				int num2 = i;
				val = pivots[i].parent.InverseTransformDirection(-panel.forward);
				array2[num2] = ((Vector3)(ref val)).normalized;
			}
		}

		internal void Reset()
		{
			value = int.MinValue;
		}

		internal void Show(int next, float dt, bool immediate)
		{
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			bool flag = immediate || value == int.MinValue || next < 0 || value < 0;
			if (next != value || flag)
			{
				int num = 100;
				int num2 = 0;
				while (num2 < 3)
				{
					int num3 = ((next < 0) ? 10 : (next / num % 10));
					if (flag)
					{
						shown[num2] = (target[num2] = num3);
						elapsed[num2] = 0.25f;
						digits[num2].text = Labels[num3];
					}
					else if (target[num2] != num3)
					{
						target[num2] = num3;
						if (elapsed[num2] >= 0.25f)
						{
							elapsed[num2] = 0f;
							direction[num2] = ((next > value) ? 1f : (-1f));
						}
					}
					num2++;
					num /= 10;
				}
				value = next;
			}
			for (int i = 0; i < 3; i++)
			{
				float num4 = elapsed[i];
				elapsed[i] = Mathf.Min(0.25f, elapsed[i] + Mathf.Max(0f, dt));
				if (num4 < 0.125f && elapsed[i] >= 0.125f)
				{
					shown[i] = target[i];
					digits[i].text = Labels[shown[i]];
				}
				if (elapsed[i] >= 0.25f && shown[i] != target[i])
				{
					elapsed[i] = 0f;
				}
				float num5 = elapsed[i] / 0.25f;
				float num6 = direction[i] * ((num5 < 0.5f) ? (180f * num5) : (-180f * (1f - num5)));
				pivots[i].localRotation = Quaternion.AngleAxis(num6, axis[i]) * restRotation[i];
				pivots[i].localPosition = restPosition[i] + outward[i] * (0.016f * Mathf.Sin(Mathf.Abs(num6) * (MathF.PI / 180f)));
			}
		}
	}
	public sealed class PairingMenu : MonoBehaviour
	{
		private static PumpItem owner;

		private static bool open;

		private static bool previousCursor;

		private static bool previousMouse;

		private static bool previousControl;

		private static bool previousVisible;

		private static CursorLockMode previousLock;

		private Vector2 scroll;

		internal static bool IsOpen => open;

		internal static void Open(PumpItem box)
		{
			//IL_0067: 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)
			if (Object.op_Implicit((Object)(object)box) && box.CanOperate && !IsOpen && !GameState.inCursorMenu)
			{
				owner = box;
				open = true;
				previousCursor = GameState.inCursorMenu;
				previousMouse = MouseLook.MouseLookIsEnabled();
				previousControl = Object.op_Implicit((Object)(object)Refs.charController) && ((Collider)Refs.charController).enabled;
				previousVisible = Cursor.visible;
				previousLock = Cursor.lockState;
				GameState.inCursorMenu = true;
				MouseLook.ToggleMouseLook(false);
				Refs.SetPlayerControl(false);
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}

		internal static void Close()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (open)
			{
				open = false;
				owner = null;
				GameState.inCursorMenu = previousCursor;
				MouseLook.ToggleMouseLook(previousMouse);
				if (Object.op_Implicit((Object)(object)Refs.charController))
				{
					Refs.SetPlayerControl(previousControl);
				}
				Cursor.lockState = previousLock;
				Cursor.visible = previousVisible;
			}
		}

		private void OnDisable()
		{
			Close();
		}

		private void Update()
		{
			//IL_0051: 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)
			if (open)
			{
				if (!Object.op_Implicit((Object)(object)owner))
				{
					Close();
				}
				else if (!owner.CanOperate || !GameState.playing || GameState.currentlyLoading || GameState.recovering || !Object.op_Implicit((Object)(object)Camera.main) || Vector3.Distance(((Component)Camera.main).transform.position, ((Component)owner).transform.position) > 3f || Input.GetKeyDown((KeyCode)27))
				{
					Close();
				}
			}
		}

		private void OnGUI()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)owner) && !owner.CanOperate)
			{
				Close();
			}
			else
			{
				if (!Object.op_Implicit((Object)(object)owner))
				{
					return;
				}
				float num = Mathf.Min(500f, (float)Screen.width - 30f);
				float num2 = Mathf.Min(380f, (float)Screen.height - 30f);
				GUILayout.BeginArea(new Rect(((float)Screen.width - num) / 2f, ((float)Screen.height - num2) / 2f, num, num2), GUI.skin.box);
				GUILayout.Label("PAIR THIS CONTROLLER", Array.Empty<GUILayoutOption>());
				scroll = GUILayout.BeginScrollView(scroll, Array.Empty<GUILayoutOption>());
				int num3 = 0;
				foreach (PumpItem item in PumpWorld.Live)
				{
					if (!Object.op_Implicit((Object)(object)item) || !item.IsPump || !item.Installed || (Object)(object)item.Item.currentActualBoat != (Object)(object)owner.Item.currentActualBoat)
					{
						continue;
					}
					PumpRecord pumpRecord = PumpWorld.State.Peer(item.Record);
					if (pumpRecord != null && pumpRecord.Id != owner.Record.Id && pumpRecord.Mounted)
					{
						continue;
					}
					num3++;
					Vector3 val = owner.Item.currentActualBoat.InverseTransformPoint(((Component)item).transform.position);
					string text = ((val.x < -0.1f) ? "port" : ((val.x > 0.1f) ? "starboard" : "centre"));
					if (GUILayout.Button(PumpState.Label(item.Record) + " - " + text + " (fore/aft " + val.z.ToString("F1") + " m)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(38f) }))
					{
						if (PumpWorld.State.Peer(owner.Record) == item.Record || PumpWorld.State.Pair(owner.Record.Id, item.Record.Id, owner.Record.BoatId))
						{
							Close();
						}
						else if (Object.op_Implicit((Object)(object)NotificationUi.instance))
						{
							NotificationUi.instance.ShowNotification("Propeller is not available for pairing.");
						}
						break;
					}
				}
				if (num3 == 0)
				{
					GUILayout.Label("No available propeller.", Array.Empty<GUILayoutOption>());
				}
				GUILayout.EndScrollView();
				if (GUILayout.Button("Cancel", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
				{
					Close();
				}
				GUILayout.EndArea();
			}
		}
	}
	[HarmonyPatch(typeof(GoPointer), "PositionItemInBuyUI")]
	internal static class PropellerCarry
	{
		private static bool Prefix(GoPointer __instance, PickupableItem item)
		{
			//IL_0038: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			SaveablePrefab val = (Object.op_Implicit((Object)(object)item) ? ((Component)item).GetComponent<SaveablePrefab>() : null);
			if (!Plugin.Ready || !Object.op_Implicit((Object)(object)val) || val.prefabIndex != 606)
			{
				return true;
			}
			Transform transform = ((Component)__instance).transform;
			Vector3 val2 = transform.position + transform.forward * item.holdDistance + transform.up * item.holdHeight;
			((Component)item).transform.position = Vector3.Lerp(((Component)item).transform.position, val2, Time.deltaTime * 9f);
			if (Object.op_Implicit((Object)(object)BuyItemUI.instance) && Object.op_Implicit((Object)(object)BuyItemUI.instance.itemPos))
			{
				((Component)item).transform.rotation = BuyItemUI.instance.itemPos.rotation;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ShopItemSpawner), "Start")]
	internal static class AcademyStock
	{
		internal const string SceneName = "island 8 A Academy";

		internal const string ExtraName = "JetPump Academy controller left";

		internal const string ThirdName = "Propeller Academy controller far left";

		internal const string HugeName = "Propeller Academy huge";

		[HarmonyPrefix]
		[HarmonyPriority(0)]
		private static void Prefix(ShopItemSpawner __instance)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might