Decompiled source of DeftHands v1.2.1

DeftHands/DeftHands.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DeftHands.Compat;
using DeftHands.Configuration;
using DeftHands.Runtime;
using DeftHands.Utils;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Deft Hands")]
[assembly: AssemblyDescription("Deft Hands - intuitive mouse-drag item rotation for Sailwind, with weighted inertia. https://github.com/KeeviDev/SailwindDeftHands.git")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Keevi")]
[assembly: AssemblyProduct("Deft Hands")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("205f0518-759a-486d-82a9-cea6097352f3")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.2.1.0")]
namespace DeftHands
{
	[BepInPlugin("com.keevi.defthands", "Deft Hands", "1.2.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "com.keevi.defthands";

		public const string PLUGIN_NAME = "Deft Hands";

		public const string PLUGIN_VERSION = "1.2.1";

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				ModConfig.Bind(((BaseUnityPlugin)this).Config);
				LogSettings();
				ApplyHarmonyPatches();
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("{0} failed to load and will not activate: {1}", "Deft Hands", arg));
				return;
			}
			Log.LogInfo((object)string.Format("{0} v{1} loaded.", "Deft Hands", "1.2.1"));
		}

		private void LogSettings()
		{
			Log.LogInfo((object)"Configuration:");
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in ((BaseUnityPlugin)this).Config)
			{
				Log.LogInfo((object)$"  {item.Key.Key}: {item.Value.BoxedValue}");
			}
		}

		private static void ApplyHarmonyPatches()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Harmony val = new Harmony("com.keevi.defthands");
			val.PatchAll(Assembly.GetExecutingAssembly());
			foreach (MethodBase patchedMethod in val.GetPatchedMethods())
			{
				Log.LogInfo((object)$"Patched {patchedMethod.DeclaringType}.{patchedMethod.Name}");
			}
		}
	}
}
namespace DeftHands.Utils
{
	internal static class ReflectionUtils
	{
		public static Type FindType(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type type;
				try
				{
					type = assembly.GetType(fullName);
				}
				catch
				{
					continue;
				}
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}
	}
	internal static class PickupableItemUtils
	{
		public static bool HasCustomOnScroll(PickupableItem item)
		{
			MethodInfo method = ((object)item).GetType().GetMethod("OnScroll", BindingFlags.Instance | BindingFlags.Public);
			if (method == null)
			{
				return false;
			}
			return method.DeclaringType != typeof(PickupableItem);
		}
	}
}
namespace DeftHands.Compat
{
	internal static class NandTweaksCompat
	{
		private const string PluginTypeName = "NANDTweaks.Plugin";

		private const BindingFlags FieldFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static bool initialized;

		private static FieldInfo rotateKeyField;

		private static FieldInfo pushKeyField;

		public static bool IsRotateKeyPressed()
		{
			EnsureInitialized();
			return IsShortcutPressed(rotateKeyField);
		}

		public static bool IsPushKeyPressed()
		{
			EnsureInitialized();
			return IsShortcutPressed(pushKeyField);
		}

		public static bool IsAnyKeyPressed()
		{
			if (!IsRotateKeyPressed())
			{
				return IsPushKeyPressed();
			}
			return true;
		}

		private static void EnsureInitialized()
		{
			if (!initialized)
			{
				initialized = true;
				Type type = ReflectionUtils.FindType("NANDTweaks.Plugin");
				if (!(type == null))
				{
					rotateKeyField = type.GetField("rotateItemKey", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					pushKeyField = type.GetField("pushItemKey", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
		}

		private static bool IsShortcutPressed(FieldInfo configEntryField)
		{
			//IL_001e: 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)
			if (configEntryField == null)
			{
				return false;
			}
			if (!(configEntryField.GetValue(null) is ConfigEntry<KeyboardShortcut> val))
			{
				return false;
			}
			KeyboardShortcut value = val.Value;
			return ((KeyboardShortcut)(ref value)).IsPressed();
		}
	}
	internal static class HooksHangMoreCompat
	{
		public const float MaxSwing = 90f;

		private const string AddOnsTypeName = "HooksHangMore.PickupableItemAddOns";

		private static bool initialized;

		private static Type addOnsType;

		private static FieldInfo swingField;

		public static Component GetSwingOwner(PickupableItem item)
		{
			EnsureInitialized();
			if (!(swingField != null))
			{
				return null;
			}
			return ((Component)item).GetComponent(addOnsType);
		}

		public static float GetSwing(Component owner)
		{
			return (float)swingField.GetValue(owner);
		}

		public static void SetSwing(Component owner, float swing)
		{
			swingField.SetValue(owner, Mathf.Clamp(swing, -90f, 90f));
		}

		private static void EnsureInitialized()
		{
			if (!initialized)
			{
				initialized = true;
				addOnsType = ReflectionUtils.FindType("HooksHangMore.PickupableItemAddOns");
				if (!(addOnsType == null))
				{
					swingField = addOnsType.GetField("heldRotationYOffset", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
		}
	}
}
namespace DeftHands.Patches
{
	internal static class HeldItemTracker
	{
		public static void SetCurrentItem(PickupableItem item, bool wasAttached)
		{
			RotationHandler.GetInstance().SetCurrentItem(item);
			PushPullHandler.GetInstance().SetCurrentItem(item);
			WallAttachmentRoll.SetCurrentItem(item, wasAttached);
		}
	}
	[HarmonyPatch(typeof(GoPointer), "PickUpItem")]
	public static class PickUpItemPatch
	{
		public static void Prefix(PickupableItem item, out bool __state)
		{
			ShipItem val = (ShipItem)(object)((item is ShipItem) ? item : null);
			__state = val != null && (Object)(object)val.GetItemRigidbody() != (Object)null && val.GetItemRigidbody().attached;
		}

		public static void Postfix(PickupableItem item, bool __state)
		{
			if ((Object)(object)item != (Object)null)
			{
				HeldItemTracker.SetCurrentItem(item, __state);
			}
		}
	}
	[HarmonyPatch(typeof(GoPointer), "DropItem")]
	public static class DropItemPatch
	{
		public static void Prefix()
		{
			HeldItemTracker.SetCurrentItem(null, wasAttached: false);
		}
	}
	[HarmonyPatch(typeof(PickupableItem), "OnScroll")]
	public static class ScrollWheelPatch
	{
		private const float ScrollInputPerDistance = 40f;

		public static bool Prefix(float input, PickupableItem __instance)
		{
			if (PickupableItemUtils.HasCustomOnScroll(__instance))
			{
				return true;
			}
			if (ModConfig.PushPullScrollEnabled.Value && !NandTweaksCompat.IsAnyKeyPressed())
			{
				PushPullHandler.GetInstance().Nudge(input / 40f);
				return false;
			}
			if (RotationHandler.GetInstance().IsRotating)
			{
				return false;
			}
			return ModConfig.LegacyRotationEnabled.Value;
		}
	}
	internal static class AltInteractionBlocker
	{
		private static bool isPressSuppressed;

		public static bool FilterDown(bool isDown)
		{
			if (isDown)
			{
				isPressSuppressed = RotationHandler.GetInstance().IsRotating;
			}
			if (isDown)
			{
				return !isPressSuppressed;
			}
			return false;
		}

		public static bool FilterHeld(bool isHeld)
		{
			if (!isHeld)
			{
				isPressSuppressed = false;
				return false;
			}
			if (!isPressSuppressed)
			{
				return !RotationHandler.GetInstance().IsRotating;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(GoPointer), "AltButtonDown")]
	public static class AltButtonDownPatch
	{
		public static void Postfix(ref bool __result)
		{
			__result = AltInteractionBlocker.FilterDown(__result);
		}
	}
	[HarmonyPatch(typeof(GoPointer), "AltButtonHeld")]
	public static class AltButtonHeldPatch
	{
		public static void Postfix(ref bool __result)
		{
			__result = AltInteractionBlocker.FilterHeld(__result);
		}
	}
	[HarmonyPatch(typeof(GoPointer), "LateUpdate")]
	public static class LegacyRotationBlockPatch
	{
		private static bool shouldBlockRotation;

		[HarmonyPrefix]
		private static void Prefix(GoPointer __instance)
		{
			shouldBlockRotation = ShouldBlockRotation(__instance.GetHeldItem());
		}

		private static bool ShouldBlockRotation(PickupableItem heldItem)
		{
			if (ModConfig.LegacyRotationEnabled.Value || (Object)(object)heldItem == (Object)null)
			{
				return false;
			}
			if (PickupableItemUtils.HasCustomOnScroll(heldItem) || NandTweaksCompat.IsPushKeyPressed())
			{
				return false;
			}
			if (!GameInput.GetKey((InputName)11) && !NandTweaksCompat.IsRotateKeyPressed())
			{
				return !ModConfig.PushPullScrollEnabled.Value;
			}
			return true;
		}

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(LegacyRotationBlockPatch), "MaskScrollValue", (Type[])null, (Type[])null);
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			bool flag = false;
			for (int i = 1; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.LoadsConstant(list[i], 0.0) && CodeInstructionExtensions.IsLdloc(list[i - 1], (LocalBuilder)null))
				{
					list.Insert(i, new CodeInstruction(OpCodes.Call, (object)methodInfo));
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				Plugin.Log.LogError((object)"Could not find the scroll check to patch in GoPointer.LateUpdate - the game may have updated. Legacy Rotation Control will not be able to block scroll-wheel rotation.");
			}
			return list;
		}

		private static float MaskScrollValue(float original)
		{
			if (!shouldBlockRotation)
			{
				return original;
			}
			return 0f;
		}
	}
	[HarmonyPatch(typeof(MouseLook), "Update")]
	public static class DisableCameraRotationPatch
	{
		public static bool Prefix()
		{
			return !RotationHandler.GetInstance().IsRotating;
		}
	}
	[HarmonyPatch(typeof(MouseLook), "Update")]
	public static class MouseLookRotateHUnblockPatch
	{
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(GameInput), "GetKey", new Type[1] { typeof(InputName) }, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(MouseLookRotateHUnblockPatch), "MaskRotateHCheck", (Type[])null, (Type[])null);
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.Calls(list[i], methodInfo))
				{
					list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)methodInfo2));
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				Plugin.Log.LogError((object)"Could not find the RotateH check to patch in MouseLook.Update - the game may have updated. The camera will keep ignoring input while Q is held even with Legacy Rotation Control off.");
			}
			return list;
		}

		private static bool MaskRotateHCheck(bool original)
		{
			return ModConfig.LegacyRotationEnabled.Value && original;
		}
	}
	[HarmonyPatch(typeof(ShipItem), "Update")]
	public static class WallAttachmentRollPatch
	{
		private static readonly MethodInfo SetUpTargeterMethod = AccessTools.Method(typeof(ShipItem), "SetUpTargeter", (Type[])null, (Type[])null);

		private static readonly Action<ShipItem, Vector3, Quaternion, Mesh> SetUpTargeter = ((SetUpTargeterMethod != null) ? AccessTools.MethodDelegate<Action<ShipItem, Vector3, Quaternion, Mesh>>(SetUpTargeterMethod, (object)null, true) : null);

		public static void Postfix(ShipItem __instance, bool ___inRangeOfWall, Vector3 ___attachPos, ref Quaternion ___attachRot)
		{
			//IL_000c: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			if (___inRangeOfWall && WallAttachmentRoll.IsActive && WallAttachmentRoll.TryRollAttachment(__instance, ___attachPos, ref ___attachRot))
			{
				SetUpTargeter?.Invoke(__instance, ___attachPos, ___attachRot, ((Component)__instance).GetComponent<MeshFilter>().sharedMesh);
			}
		}
	}
	[HarmonyPatch(typeof(GoPointer), "LateUpdate")]
	public static class HeldItemRollPatch
	{
		public static void Prefix(GoPointer __instance)
		{
			WallAttachmentRoll.UnrollHeldItem(__instance.GetHeldItem());
		}

		public static void Postfix(GoPointer __instance)
		{
			WallAttachmentRoll.RollHeldItem(__instance.GetHeldItem());
		}
	}
	[HarmonyPatch(typeof(PickupableItemCollisionChecker), "GetDecollision")]
	public static class CargoPlacementOverridePatch
	{
		public static void Postfix(PickupableItemCollisionChecker __instance, ref Vector3 __result)
		{
			//IL_0007: 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_0019: Unknown result type (might be due to invalid IL or missing references)
			if (PushPullHandler.GetInstance().UpdatePushOutOverride(__instance, __result))
			{
				__result = Vector3.zero;
			}
		}
	}
}
namespace DeftHands.Runtime
{
	public class RotationHandler : MonoBehaviour
	{
		private const float QuadrantZeroDeadzoneDegrees = 2f;

		private const float WeightEffectThreshold = 0f;

		private const float WeightEffectCap = 900f;

		private const float WeightCurvePower = 0.4f;

		private const float StandardSmoothTime = 0.25f;

		private const float LightSmoothTime = 0.1f;

		private const float SingleAxisSpeedMultiplier = 2f;

		private const float MinAppliedInput = 0.001f;

		private static readonly FieldInfo BigItemLocalRotField = AccessTools.Field(typeof(GoPointer), "bigItemLocalRot");

		private static RotationHandler instance;

		private PickupableItem currentItem;

		private float smoothedX;

		private float smoothedY;

		private float dampVelocityX;

		private float dampVelocityY;

		private float quadrantRawOffset;

		private float lastAppliedQuadrantOffset;

		public bool IsRotating
		{
			get
			{
				if (ModConfig.MouseRotationEnabled.Value && ModInput.IsRotationActivationKeyHeld() && (Object)(object)currentItem != (Object)null)
				{
					return (Object)(object)currentItem.held != (Object)null;
				}
				return false;
			}
		}

		public static RotationHandler GetInstance()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			if ((Object)(object)instance == (Object)null)
			{
				GameObject val = new GameObject("DeftHands_RotationHandler");
				instance = val.AddComponent<RotationHandler>();
				Object.DontDestroyOnLoad((Object)val);
			}
			return instance;
		}

		public void SetCurrentItem(PickupableItem item)
		{
			currentItem = item;
			ResetWeightState();
			lastAppliedQuadrantOffset = (quadrantRawOffset = (((Object)(object)item != (Object)null) ? item.heldRotationOffset : 0f));
		}

		private void Update()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!IsRotating)
			{
				ResetWeightState();
				WallAttachmentRoll.RecenterDeadzone();
				return;
			}
			Vector2 val = ReadMouseInput();
			if (!(Mathf.Abs(val.x) < 0.001f) || !(Mathf.Abs(val.y) < 0.001f))
			{
				RotateHeldItem(val.x, val.y);
			}
		}

		private Vector2 ReadMouseInput()
		{
			//IL_007b: 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)
			float axis = Input.GetAxis("Mouse X");
			float axis2 = Input.GetAxis("Mouse Y");
			if (!ModConfig.RotationInertiaEnabled.Value)
			{
				ResetWeightState();
				return new Vector2(axis, axis2);
			}
			float num = GetHeaviness() * GetPresetSmoothTime();
			smoothedX = Mathf.SmoothDamp(smoothedX, axis, ref dampVelocityX, num);
			smoothedY = Mathf.SmoothDamp(smoothedY, axis2, ref dampVelocityY, num);
			return new Vector2(smoothedX, smoothedY);
		}

		private void ResetWeightState()
		{
			smoothedX = 0f;
			smoothedY = 0f;
			dampVelocityX = 0f;
			dampVelocityY = 0f;
		}

		private static float GetPresetSmoothTime()
		{
			if (ModConfig.WeightPreset.Value != RotationWeightPreset.Light)
			{
				return 0.25f;
			}
			return 0.1f;
		}

		private float GetHeaviness()
		{
			PickupableItem obj = currentItem;
			ShipItem val = (ShipItem)(object)((obj is ShipItem) ? obj : null);
			if (val == null)
			{
				return 0f;
			}
			return Mathf.Pow(Mathf.InverseLerp(0f, 900f, val.mass), 0.4f);
		}

		private void RotateHeldItem(float horizontalInput, float verticalInput)
		{
			if (PickupableItemUtils.HasCustomOnScroll(currentItem))
			{
				return;
			}
			Camera main = Camera.main;
			if (!((Object)(object)main == (Object)null))
			{
				float value = ModConfig.RotationSensitivity.Value;
				float num = value * 2f;
				float num2 = ApplyInversion(verticalInput, ModConfig.InvertVertical);
				bool flag = IsAlternativeAxisActive();
				if (WallAttachmentRoll.IsActive && !currentItem.big && !flag)
				{
					WallAttachmentRoll.AddRollInput((0f - ApplyInversion(horizontalInput, ModConfig.InvertRoll)) * num);
				}
				if (currentItem.big)
				{
					RotateBigItem(currentItem, main, horizontalInput, num2, value, flag);
					return;
				}
				if (currentItem is ShipItemQuadrant)
				{
					RotateQuadrant(num2 * num);
					return;
				}
				PickupableItem obj = currentItem;
				obj.heldRotationOffset += num2 * num;
			}
		}

		private static bool IsAlternativeAxisActive()
		{
			return ModConfig.UseAlternativeRotationAxis.Value ^ ModInput.IsAxisSwapKeyHeld();
		}

		private static void RotateBigItem(PickupableItem item, Camera mainCamera, float horizontalInput, float tiltInput, float sensitivity, bool useAlternativeAxis)
		{
			//IL_0030: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)mainCamera).transform;
			if (useAlternativeAxis)
			{
				((Component)item).transform.Rotate(transform.up, (0f - ApplyInversion(horizontalInput, ModConfig.InvertTurn)) * sensitivity, (Space)0);
			}
			else
			{
				RollBigItem(item, transform.forward, (0f - ApplyInversion(horizontalInput, ModConfig.InvertRoll)) * sensitivity);
			}
			((Component)item).transform.Rotate(transform.right, tiltInput * sensitivity, (Space)0);
			if (WallAttachmentRoll.IsActive)
			{
				WallAttachmentRoll.HoldBigItemUpright(((Component)item).transform);
			}
			StoreBigItemRotation(item);
		}

		private static void RollBigItem(PickupableItem item, Vector3 axis, float degrees)
		{
			//IL_001b: 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)
			if (WallAttachmentRoll.IsActive)
			{
				WallAttachmentRoll.RollBigItem(((Component)item).transform, axis, degrees);
			}
			else
			{
				((Component)item).transform.Rotate(axis, degrees, (Space)0);
			}
		}

		private static float ApplyInversion(float input, ConfigEntry<bool> invert)
		{
			if (!invert.Value)
			{
				return input;
			}
			return 0f - input;
		}

		private static void StoreBigItemRotation(PickupableItem item)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!(BigItemLocalRotField == null))
			{
				Quaternion rotation = ((Component)item.held).transform.rotation;
				BigItemLocalRotField.SetValue(item.held, Quaternion.Inverse(rotation) * ((Component)item).transform.rotation);
				item.heldRotationOffset = 0f;
			}
		}

		private void RotateQuadrant(float angle)
		{
			if (!Mathf.Approximately(currentItem.heldRotationOffset, lastAppliedQuadrantOffset))
			{
				quadrantRawOffset = currentItem.heldRotationOffset;
			}
			quadrantRawOffset += angle;
			lastAppliedQuadrantOffset = ApplyDeadzone(quadrantRawOffset, 2f);
			currentItem.heldRotationOffset = lastAppliedQuadrantOffset;
		}

		private static float ApplyDeadzone(float raw, float zone)
		{
			if (!(Mathf.Abs(raw) <= zone))
			{
				return raw;
			}
			return 0f;
		}
	}
	public class PushPullHandler : MonoBehaviour
	{
		private const float SmoothTime = 0.12f;

		private const float SettleThreshold = 0.0005f;

		private const float GamePushOutRate = 3f;

		private const float PushBackAveragingTime = 0.2f;

		private const float PushOutOverrideStartRate = 0.7f;

		private const float PushOutOverrideStopRate = 0.45f;

		private const float MinHoldDistance = 0.5f;

		private const float MaxHoldDistance = 2f;

		private const float MinBigItemDistance = 1f;

		private const float MaxBigItemDistance = 3f;

		private static readonly FieldInfo BigItemLocalPosField = AccessTools.Field(typeof(GoPointer), "bigItemLocalPos");

		private static readonly FieldInfo DecolLocalPosField = AccessTools.Field(typeof(GoPointer), "decolLocalPos");

		private static PushPullHandler instance;

		private PickupableItem currentItem;

		private float requestedOffset;

		private float appliedOffset;

		private float smoothVelocity;

		private float pushBackRate;

		private bool overridesPushOut;

		public static PushPullHandler GetInstance()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			if ((Object)(object)instance == (Object)null)
			{
				GameObject val = new GameObject("DeftHands_PushPullHandler");
				instance = val.AddComponent<PushPullHandler>();
				Object.DontDestroyOnLoad((Object)val);
			}
			return instance;
		}

		public bool UpdatePushOutOverride(PickupableItemCollisionChecker collisionChecker, Vector3 pushOut)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)currentItem == (Object)null || (Object)(object)currentItem.colChecker != (Object)(object)collisionChecker || (Object)(object)currentItem.held == (Object)null)
			{
				return false;
			}
			if (requestedOffset == appliedOffset)
			{
				pushBackRate = 0f;
				overridesPushOut = false;
				return false;
			}
			float num = Mathf.Sign(requestedOffset - appliedOffset);
			float num2 = Vector3.Dot(((Component)currentItem).transform.TransformVector(pushOut), ((Component)currentItem.held).transform.forward) * num;
			float num3 = Mathf.Max(0f, 0f - num2) * 3f;
			pushBackRate = Mathf.Lerp(pushBackRate, num3, 1f - Mathf.Exp((0f - Time.deltaTime) / 0.2f));
			if (pushBackRate >= 0.7f)
			{
				overridesPushOut = true;
			}
			else if (pushBackRate < 0.45f)
			{
				overridesPushOut = false;
			}
			return overridesPushOut;
		}

		public void SetCurrentItem(PickupableItem item)
		{
			currentItem = item;
			ResetSmoothing();
		}

		public void Nudge(float delta)
		{
			if (!((Object)(object)currentItem == (Object)null))
			{
				requestedOffset += delta;
			}
		}

		private void Update()
		{
			if ((Object)(object)currentItem == (Object)null || (Object)(object)currentItem.held == (Object)null)
			{
				SetCurrentItem(null);
			}
			else if (requestedOffset != appliedOffset)
			{
				float num = ((Mathf.Abs(requestedOffset - appliedOffset) < 0.0005f) ? requestedOffset : Mathf.SmoothDamp(appliedOffset, requestedOffset, ref smoothVelocity, 0.12f));
				bool num2 = MoveHeldItem(num - appliedOffset);
				appliedOffset = num;
				if (!num2 || appliedOffset == requestedOffset)
				{
					ResetSmoothing();
				}
			}
		}

		private void ResetSmoothing()
		{
			requestedOffset = 0f;
			appliedOffset = 0f;
			smoothVelocity = 0f;
			pushBackRate = 0f;
			overridesPushOut = false;
		}

		private bool MoveHeldItem(float step)
		{
			float num = currentItem.holdDistance + step;
			currentItem.holdDistance = ClampTowardRange(currentItem.holdDistance, num, 0.5f, 2f);
			bool result = currentItem.holdDistance == num;
			if (currentItem.big && BigItemLocalPosField != null && DecolLocalPosField != null)
			{
				result = MoveBigItem(step);
			}
			return result;
		}

		private bool MoveBigItem(float step)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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)
			Vector3 val = (Vector3)DecolLocalPosField.GetValue(currentItem.held);
			float num = val.z + step;
			val.z = ClampTowardRange(val.z, num, 1f, 3f);
			DecolLocalPosField.SetValue(currentItem.held, val);
			Vector3 val2 = (Vector3)BigItemLocalPosField.GetValue(currentItem.held);
			val2.z = val.z;
			BigItemLocalPosField.SetValue(currentItem.held, val2);
			return val.z == num;
		}

		private static float ClampTowardRange(float current, float requested, float min, float max)
		{
			return Mathf.Clamp(requested, Mathf.Min(current, min), Mathf.Max(current, max));
		}
	}
	internal static class WallAttachmentRoll
	{
		private const float UprightDeadzoneDegrees = 18f;

		private const float MaxWallFacingY = 0.8f;

		private const float UprightTolerance = 0.01f;

		private const float HalfDeadzone = 9f;

		private const float InputPeriod = 378f;

		private static ShipItem currentItem;

		private static float rollInput;

		private static bool isBigItemUpright;

		private static float uprightInput;

		private static float heldItemRoll;

		private static Component hookSwingOwner;

		private static float lastWrittenSwing;

		public static bool IsActive
		{
			get
			{
				if ((Object)(object)currentItem != (Object)null)
				{
					if (!((Object)(object)hookSwingOwner != (Object)null))
					{
						return ModConfig.WallAttachmentRotationEnabled.Value;
					}
					return true;
				}
				return false;
			}
		}

		public static void SetCurrentItem(PickupableItem item, bool wasAttached)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)currentItem != (Object)null)
			{
				RollHeldItem((PickupableItem)(object)currentItem);
			}
			ShipItem val = (ShipItem)(object)((item is ShipItem) ? item : null);
			currentItem = ((val != null && val.wallAttachment) ? val : null);
			rollInput = 0f;
			uprightInput = 0f;
			isBigItemUpright = false;
			hookSwingOwner = null;
			heldItemRoll = 0f;
			if ((Object)(object)currentItem == (Object)null)
			{
				return;
			}
			if (((PickupableItem)currentItem).big)
			{
				Vector3 up = AttachmentSpace.UpInWorld(currentItem);
				isBigItemUpright = FacesWall(((Component)currentItem).transform.forward, up) && IsUpright(MeasureRoll(((Component)currentItem).transform.rotation, up));
				return;
			}
			hookSwingOwner = HooksHangMoreCompat.GetSwingOwner((PickupableItem)(object)currentItem);
			if ((Object)(object)hookSwingOwner != (Object)null)
			{
				lastWrittenSwing = HooksHangMoreCompat.GetSwing(hookSwingOwner);
				rollInput = RollToInput(lastWrittenSwing);
			}
			else if (wasAttached)
			{
				rollInput = RollToInput(ReadAttachedRoll(currentItem));
				heldItemRoll = InputToRoll(rollInput);
			}
		}

		public static void AddRollInput(float degrees)
		{
			if ((Object)(object)hookSwingOwner != (Object)null)
			{
				AddHookSwingInput(degrees);
			}
			else
			{
				rollInput = Mathf.Repeat(rollInput + degrees + 189f, 378f) - 189f;
			}
		}

		public static void RecenterDeadzone()
		{
			if (Mathf.Abs(rollInput) <= 9f)
			{
				rollInput = 0f;
			}
			uprightInput = 0f;
		}

		public static void RollBigItem(Transform item, Vector3 axis, float degrees)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			Vector3 up = AttachmentSpace.UpInWorld(currentItem);
			if (!FacesWall(item.forward, up))
			{
				isBigItemUpright = false;
				item.Rotate(axis, degrees, (Space)0);
				return;
			}
			if (isBigItemUpright)
			{
				float num = uprightInput + degrees;
				if (Mathf.Abs(num) <= 9f)
				{
					uprightInput = num;
					return;
				}
				isBigItemUpright = false;
				item.Rotate(axis, num - Mathf.Sign(num) * 9f, (Space)0);
				return;
			}
			float rollBefore = MeasureRoll(item.rotation, up);
			item.Rotate(axis, degrees, (Space)0);
			float num2 = MeasureRoll(item.rotation, up);
			if (CrossedUpright(rollBefore, num2))
			{
				EnterDeadzone(item, up, rollBefore, Mathf.Abs(num2));
			}
		}

		public static void HoldBigItemUpright(Transform item)
		{
			//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_0014: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			if (isBigItemUpright)
			{
				Vector3 up = AttachmentSpace.UpInWorld(currentItem);
				if (FacesWall(item.forward, up))
				{
					SetRoll(item, up, 0f);
				}
				else
				{
					isBigItemUpright = false;
				}
			}
		}

		public static bool TryRollAttachment(ShipItem item, Vector3 attachPos, ref Quaternion attachRot)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0047: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0087: 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)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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)
			if (!IsActive || (Object)(object)item != (Object)(object)currentItem || (Object)(object)hookSwingOwner != (Object)null)
			{
				return false;
			}
			Quaternion val = AttachmentSpace.ToAttachmentSpace(item, ((Component)item).transform.rotation);
			Vector3 val2 = attachRot * Vector3.forward;
			if (!FacesWall(val2, Vector3.up))
			{
				Camera main = Camera.main;
				if ((Object)(object)main == (Object)null)
				{
					return false;
				}
				Vector3 val3 = AttachmentSpace.ToAttachmentSpace(item, ((Component)main).transform.position);
				attachRot = FaceSurfaceAsSeen(val, val2, attachPos - val3);
				return true;
			}
			float num = (((PickupableItem)item).big ? MeasureRoll(val, Vector3.up) : InputToRoll(rollInput));
			if (num == 0f)
			{
				return false;
			}
			attachRot *= Quaternion.AngleAxis(num, Vector3.forward);
			return true;
		}

		public static void UnrollHeldItem(PickupableItem item)
		{
			//IL_002e: 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_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)
			if (!((Object)(object)currentItem == (Object)null) && !((Object)(object)item != (Object)(object)currentItem) && heldItemRoll != 0f)
			{
				Transform transform = ((Component)item).transform;
				transform.rotation *= Quaternion.AngleAxis(0f - heldItemRoll, Vector3.forward);
				heldItemRoll = 0f;
			}
		}

		public static void RollHeldItem(PickupableItem item)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)currentItem == (Object)null) && !((Object)(object)item != (Object)(object)currentItem))
			{
				float num = ((IsActive && !((PickupableItem)currentItem).big && (Object)(object)hookSwingOwner == (Object)null) ? InputToRoll(rollInput) : 0f);
				if (num != heldItemRoll)
				{
					Transform transform = ((Component)item).transform;
					transform.rotation *= Quaternion.AngleAxis(num - heldItemRoll, Vector3.forward);
				}
				heldItemRoll = num;
			}
		}

		private static void AddHookSwingInput(float degrees)
		{
			float swing = HooksHangMoreCompat.GetSwing(hookSwingOwner);
			if (swing != lastWrittenSwing)
			{
				rollInput = RollToInput(swing);
			}
			float num = 99f;
			rollInput = Mathf.Clamp(rollInput + degrees, 0f - num, num);
			lastWrittenSwing = InputToRoll(rollInput);
			HooksHangMoreCompat.SetSwing(hookSwingOwner, lastWrittenSwing);
		}

		private static void EnterDeadzone(Transform item, Vector3 up, float rollBefore, float overshoot)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Sign(rollBefore) * (9f - overshoot);
			if (Mathf.Abs(num) <= 9f)
			{
				SetRoll(item, up, 0f);
				isBigItemUpright = true;
				uprightInput = num;
			}
			else
			{
				SetRoll(item, up, (0f - Mathf.Sign(rollBefore)) * (overshoot - 18f));
			}
		}

		private static bool CrossedUpright(float rollBefore, float rollAfter)
		{
			if (Mathf.Abs(rollBefore) < 90f && Mathf.Abs(rollAfter) < 90f)
			{
				if (!IsUpright(rollAfter))
				{
					return Mathf.Sign(rollBefore) != Mathf.Sign(rollAfter);
				}
				return true;
			}
			return false;
		}

		private static float ReadAttachedRoll(ShipItem item)
		{
			//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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)item.GetItemRigidbody()).transform;
			if (FacesWall(transform.forward, Vector3.up))
			{
				return MeasureRoll(transform.rotation, Vector3.up);
			}
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return 0f;
			}
			Quaternion rotation = ((Component)((PickupableItem)item).held).transform.rotation * Quaternion.Euler(((PickupableItem)item).heldRotationOffset, 0f, 0f);
			Quaternion val = AttachmentSpace.ToAttachmentSpace(item, rotation);
			Vector3 val2 = val * Vector3.forward;
			Vector3 viewDirection = transform.position - AttachmentSpace.ToAttachmentSpace(item, ((Component)main).transform.position);
			Vector3 val3 = SeenFromSurface(transform.up, viewDirection, val2);
			if (!(val3 == Vector3.zero))
			{
				return Vector3.SignedAngle(val * Vector3.up, val3, val2);
			}
			return 0f;
		}

		private static Quaternion FaceSurfaceAsSeen(Quaternion heldRotation, Vector3 intoSurface, Vector3 viewDirection)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_003a: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0032: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = SeenFromSurface(heldRotation * Vector3.up, viewDirection, intoSurface);
			if (val == Vector3.zero)
			{
				return Quaternion.FromToRotation(heldRotation * Vector3.forward, intoSurface) * heldRotation;
			}
			return Quaternion.LookRotation(intoSurface, val);
		}

		private static Vector3 SeenFromSurface(Vector3 direction, Vector3 viewDirection, Vector3 normal)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.Cross(viewDirection, direction);
			Vector3 val2 = Vector3.Cross(normal, val);
			if (((Vector3)(ref val2)).sqrMagnitude < 1E-08f)
			{
				return Vector3.zero;
			}
			if (!(Vector3.Dot(val2, direction) < 0f))
			{
				return ((Vector3)(ref val2)).normalized;
			}
			return -((Vector3)(ref val2)).normalized;
		}

		private static float MeasureRoll(Quaternion rotation, Vector3 up)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = rotation * Vector3.forward;
			if (!FacesWall(val, up))
			{
				return 0f;
			}
			return Vector3.SignedAngle(Quaternion.LookRotation(val, up) * Vector3.up, rotation * Vector3.up, val);
		}

		private static void SetRoll(Transform item, Vector3 up, float roll)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			item.Rotate(item.forward, roll - MeasureRoll(item.rotation, up), (Space)0);
		}

		private static bool FacesWall(Vector3 forward, Vector3 up)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return Mathf.Abs(Vector3.Dot(forward, up)) <= 0.8f;
		}

		private static bool IsUpright(float roll)
		{
			return Mathf.Abs(roll) < 0.01f;
		}

		private static float InputToRoll(float input)
		{
			if (!(Mathf.Abs(input) <= 9f))
			{
				return input - Mathf.Sign(input) * 9f;
			}
			return 0f;
		}

		private static float RollToInput(float roll)
		{
			if (!IsUpright(roll))
			{
				return roll + Mathf.Sign(roll) * 9f;
			}
			return 0f;
		}
	}
	internal static class AttachmentSpace
	{
		private static readonly FieldInfo OnBoatField = AccessTools.Field(typeof(ItemRigidbody), "onBoat");

		private static readonly FieldRef<ItemRigidbody, bool> IsBodyOnBoat = ((OnBoatField != null) ? AccessTools.FieldRefAccess<ItemRigidbody, bool>(OnBoatField) : null);

		public static Vector3 ToAttachmentSpace(ShipItem item, Vector3 point)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			if (!IsOnBoat(item))
			{
				return point;
			}
			return item.currentWalkCol.TransformPoint(item.currentActualBoat.InverseTransformPoint(point));
		}

		public static Quaternion ToAttachmentSpace(ShipItem item, Quaternion rotation)
		{
			//IL_0010: 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_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_0008: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOnBoat(item))
			{
				return rotation;
			}
			return item.currentWalkCol.rotation * Quaternion.Inverse(item.currentActualBoat.rotation) * rotation;
		}

		public static Vector3 UpInWorld(ShipItem item)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOnBoat(item))
			{
				return Vector3.up;
			}
			return item.currentActualBoat.rotation * Quaternion.Inverse(item.currentWalkCol.rotation) * Vector3.up;
		}

		private static bool IsOnBoat(ShipItem item)
		{
			if ((Object)(object)item.currentWalkCol == (Object)null || (Object)(object)item.currentActualBoat == (Object)null)
			{
				return false;
			}
			if (IsBodyOnBoat != null)
			{
				return IsBodyOnBoat.Invoke(item.GetItemRigidbody());
			}
			return true;
		}
	}
}
namespace DeftHands.Configuration
{
	internal static class ModConfig
	{
		private const string HeldItemControlSection = "Held Item Control";

		private const string AxisInversionSection = "Axis Inversion";

		private const string WeightSimulationSection = "Weight Simulation";

		public static ConfigEntry<bool> MouseRotationEnabled { get; private set; }

		public static ConfigEntry<bool> PushPullScrollEnabled { get; private set; }

		public static ConfigEntry<bool> LegacyRotationEnabled { get; private set; }

		public static ConfigEntry<KeyboardShortcut> RotationActivationKey { get; private set; }

		public static ConfigEntry<float> RotationSensitivity { get; private set; }

		public static ConfigEntry<bool> UseAlternativeRotationAxis { get; private set; }

		public static ConfigEntry<KeyboardShortcut> AxisSwapKey { get; private set; }

		public static ConfigEntry<bool> WallAttachmentRotationEnabled { get; private set; }

		public static ConfigEntry<bool> InvertVertical { get; private set; }

		public static ConfigEntry<bool> InvertRoll { get; private set; }

		public static ConfigEntry<bool> InvertTurn { get; private set; }

		public static ConfigEntry<bool> RotationInertiaEnabled { get; private set; }

		public static ConfigEntry<RotationWeightPreset> WeightPreset { get; private set; }

		public static void Bind(ConfigFile config)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0087: 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_00a1: Expected O, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Expected O, but got Unknown
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Expected O, but got Unknown
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Expected O, but got Unknown
			MouseRotationEnabled = config.Bind<bool>("Held Item Control", "Mouse rotation control", true, new ConfigDescription("Rotate held items with mouse movement while holding the Rotation Activation Key below.", (AcceptableValueBase)null, Array.Empty<object>()));
			PushPullScrollEnabled = config.Bind<bool>("Held Item Control", "Push/pull on scroll wheel", true, new ConfigDescription("Scroll the mouse wheel (without holding a modifier key) to move the held item closer or farther, instead of rotating it around its main axis.", (AcceptableValueBase)null, Array.Empty<object>()));
			LegacyRotationEnabled = config.Bind<bool>("Held Item Control", "Legacy rotation control", true, new ConfigDescription("Enable the game's original scroll-wheel rotation (plain scroll, plus the Q axis), and NANDTweaks' third axis if you have that mod installed. Turn this off to rotate items with the mouse-drag method only.", (AcceptableValueBase)null, Array.Empty<object>()));
			RotationActivationKey = config.Bind<KeyboardShortcut>("Held Item Control", "Rotation activation key", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), new ConfigDescription("The key or mouse button you hold down while moving the mouse to rotate the held item.", (AcceptableValueBase)null, Array.Empty<object>()));
			RotationSensitivity = config.Bind<float>("Held Item Control", "Rotation sensitivity", 2f, new ConfigDescription("How fast items rotate with mouse movement.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			UseAlternativeRotationAxis = config.Bind<bool>("Held Item Control", "Alternative rotation axis", false, new ConfigDescription("Changes which axis left/right mouse movement rotates the item around. By default, it rolls the item around the direction you're looking. Turn this on to instead yaw it around the vertical axis.", (AcceptableValueBase)null, Array.Empty<object>()));
			AxisSwapKey = config.Bind<KeyboardShortcut>("Held Item Control", "Axis swap key", new KeyboardShortcut((KeyCode)324, Array.Empty<KeyCode>()), new ConfigDescription("While held together with the Rotation Activation Key, temporarily swaps which axis left/right mouse movement rotates big items around, overriding Alternative Rotation Axis for as long as it's held.", (AcceptableValueBase)null, Array.Empty<object>()));
			WallAttachmentRotationEnabled = config.Bind<bool>("Held Item Control", "Wall attachment rotation", true, new ConfigDescription("Lets you control the angle items are hung on walls, ceilings and floors: roll a wall-attachable item with the mouse and it attaches at that angle.", (AcceptableValueBase)null, Array.Empty<object>()));
			InvertVertical = config.Bind<bool>("Axis Inversion", "Invert vertical", false, new ConfigDescription("Reverses which way up/down mouse movement tilts the held item.", (AcceptableValueBase)null, Array.Empty<object>()));
			InvertRoll = config.Bind<bool>("Axis Inversion", "Invert roll", false, new ConfigDescription("Reverses which way left/right mouse movement rolls items.", (AcceptableValueBase)null, Array.Empty<object>()));
			InvertTurn = config.Bind<bool>("Axis Inversion", "Invert turn", false, new ConfigDescription("Reverses which way left/right mouse movement turns items around the vertical axis (Alternative Rotation Axis, or while holding the Axis Swap Key).", (AcceptableValueBase)null, Array.Empty<object>()));
			RotationInertiaEnabled = config.Bind<bool>("Weight Simulation", "Rotation inertia", true, new ConfigDescription("Makes held items feel like they have weight when you rotate them: heavier items take a moment to speed up, and keep drifting briefly after you stop moving the mouse. Turn off for instant, 1:1 mouse response.", (AcceptableValueBase)null, Array.Empty<object>()));
			WeightPreset = config.Bind<RotationWeightPreset>("Weight Simulation", "Weight preset", RotationWeightPreset.Standard, new ConfigDescription("How strongly items feel weighted while rotating. Standard is the full effect; Light is a much subtler version.", (AcceptableValueBase)null, Array.Empty<object>()));
			KeepPushPullDependentOnMouseRotation();
		}

		private static void KeepPushPullDependentOnMouseRotation()
		{
			DisablePushPullWithoutMouseRotation();
			MouseRotationEnabled.SettingChanged += delegate
			{
				DisablePushPullWithoutMouseRotation();
			};
			PushPullScrollEnabled.SettingChanged += delegate
			{
				if (PushPullScrollEnabled.Value && !MouseRotationEnabled.Value)
				{
					MouseRotationEnabled.Value = true;
				}
			};
		}

		private static void DisablePushPullWithoutMouseRotation()
		{
			if (!MouseRotationEnabled.Value && PushPullScrollEnabled.Value)
			{
				PushPullScrollEnabled.Value = false;
			}
		}
	}
	internal static class ModInput
	{
		public static bool IsRotationActivationKeyHeld()
		{
			return IsMainKeyHeld(ModConfig.RotationActivationKey);
		}

		public static bool IsAxisSwapKeyHeld()
		{
			return IsMainKeyHeld(ModConfig.AxisSwapKey);
		}

		private static bool IsMainKeyHeld(ConfigEntry<KeyboardShortcut> shortcut)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = shortcut.Value;
			return Input.GetKey(((KeyboardShortcut)(ref value)).MainKey);
		}
	}
	public enum RotationWeightPreset
	{
		Standard,
		Light
	}
}