Decompiled source of Hand Quickbelts v0.4.2

quaternion.hqb.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("quaternion")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Configurable H3VR quickbelt slots attached below each hand.")]
[assembly: AssemblyFileVersion("0.4.2.0")]
[assembly: AssemblyInformationalVersion("0.4.2")]
[assembly: AssemblyProduct("quaternion.hqb")]
[assembly: AssemblyTitle("Hand Quickbelts")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.2.0")]
[module: UnverifiableCode]
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace HandQuickbelts
{
	internal sealed class HandQuickbeltController
	{
		private const float MillimetersToMeters = 0.001f;

		private readonly List<FVRQuickBeltSlot> _slots = new List<FVRQuickBeltSlot>();

		private readonly List<FVRQuickBeltSlot> _leftSlots = new List<FVRQuickBeltSlot>();

		private readonly List<FVRQuickBeltSlot> _rightSlots = new List<FVRQuickBeltSlot>();

		private FVRPlayerBody _body;

		private GameObject _leftRoot;

		private GameObject _rightRoot;

		private HandQuickbeltAdjustmentHandle _leftHandle;

		private HandQuickbeltAdjustmentHandle _rightHandle;

		private bool _rebuildRequested;

		private bool _layoutRequested;

		private bool _templateWarningLogged;

		private float _nextTemplateLookupTime;

		internal void Tick()
		{
			FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
			if (!SceneAllowsQuickbelts(currentPlayerBody))
			{
				DisableForScene();
			}
			else if ((Object)(object)_body != (Object)(object)currentPlayerBody || (Object)(object)_leftRoot == (Object)null || (Object)(object)_rightRoot == (Object)null)
			{
				Rebuild(currentPlayerBody, dropContents: false);
			}
			else if (_rebuildRequested)
			{
				_rebuildRequested = false;
				_layoutRequested = false;
				Rebuild(currentPlayerBody, dropContents: true);
			}
			else if (_layoutRequested)
			{
				_layoutRequested = false;
				ApplyLayout();
			}
		}

		internal void RebuildAfterQuickbeltChange(FVRPlayerBody body)
		{
			if (!SceneAllowsQuickbelts(body))
			{
				DisableForScene();
			}
			else
			{
				Rebuild(body, dropContents: false);
			}
		}

		internal void RequestRebuild()
		{
			_rebuildRequested = true;
		}

		internal void RequestLayout()
		{
			_layoutRequested = true;
		}

		internal void Dispose()
		{
			RemoveSlots(dropContents: true);
			_body = null;
		}

		private void Rebuild(FVRPlayerBody body, bool dropContents)
		{
			if (!SceneAllowsQuickbelts(body) || Time.unscaledTime < _nextTemplateLookupTime)
			{
				return;
			}
			FVRQuickBeltSlot val = FindTemplate(body);
			if ((Object)(object)val == (Object)null)
			{
				_nextTemplateLookupTime = Time.unscaledTime + 1f;
				if (!_templateWarningLogged)
				{
					_templateWarningLogged = true;
					Plugin.Logger.LogWarning((object)"Native spherical quickbelt slots are not ready; retrying once per second.");
				}
				return;
			}
			_nextTemplateLookupTime = 0f;
			_templateWarningLogged = false;
			RemoveSlots(dropContents);
			_body = body;
			_leftRoot = CreateHandRoot("HQB_LeftHand", body.LeftHand);
			_rightRoot = CreateHandRoot("HQB_RightHand", body.RightHand);
			_leftHandle = CreateAdjustmentHandle(_leftRoot.transform, isLeftHand: true);
			_rightHandle = CreateAdjustmentHandle(_rightRoot.transform, isLeftHand: false);
			CreateHandSlots(_leftRoot.transform, _leftSlots, val, Plugin.LeftLargeSlots.Value, Plugin.LeftMediumSlots.Value, Plugin.LeftSmallSlots.Value);
			CreateHandSlots(_rightRoot.transform, _rightSlots, val, Plugin.RightLargeSlots.Value, Plugin.RightMediumSlots.Value, Plugin.RightSmallSlots.Value);
			ApplyLayout();
			Plugin.Logger.LogInfo((object)$"Created {_slots.Count} hand quickbelt slots.");
		}

		private static bool SceneAllowsQuickbelts(FVRPlayerBody body)
		{
			if ((Object)(object)body != (Object)null && (Object)(object)body.LeftHand != (Object)null && (Object)(object)body.RightHand != (Object)null && (Object)(object)GM.CurrentSceneSettings != (Object)null)
			{
				return GM.CurrentSceneSettings.AreQuickbeltSlotsEnabled;
			}
			return false;
		}

		private void DisableForScene()
		{
			if (_slots.Count > 0 || (Object)(object)_leftRoot != (Object)null || (Object)(object)_rightRoot != (Object)null)
			{
				RemoveSlots(dropContents: true);
				Plugin.Logger.LogInfo((object)"Removed hand quickbelt slots because the current scene disables quickbelts.");
			}
			_body = null;
			_rebuildRequested = false;
			_layoutRequested = false;
			_nextTemplateLookupTime = 0f;
			_templateWarningLogged = false;
		}

		private static GameObject CreateHandRoot(string name, Transform hand)
		{
			//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_003c: Expected O, but got Unknown
			FVRViveHand component = ((Component)hand).GetComponent<FVRViveHand>();
			Transform val = (((Object)(object)component != (Object)null && (Object)(object)component.PalmTransform != (Object)null) ? component.PalmTransform : hand);
			GameObject val2 = new GameObject(name);
			val2.transform.SetParent(val, false);
			return val2;
		}

		private static HandQuickbeltAdjustmentHandle CreateAdjustmentHandle(Transform root, bool isLeftHand)
		{
			//IL_003e: 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_0058: 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_00a4: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)val).name = (isLeftHand ? "HQB_LeftAnchorHandle" : "HQB_RightAnchorHandle");
			val.transform.SetParent(root, false);
			val.transform.localPosition = new Vector3(0f, 0.055f, 0f);
			val.transform.localScale = Vector3.one * 0.035f;
			int num = LayerMask.NameToLayer("Interactable");
			if (num >= 0)
			{
				val.layer = num;
			}
			Renderer component = val.GetComponent<Renderer>();
			Shader val2 = Shader.Find("Unlit/Color");
			if ((Object)(object)component != (Object)null && (Object)(object)val2 != (Object)null)
			{
				Material val3 = new Material(val2);
				val3.color = (isLeftHand ? new Color(1f, 0.72f, 0.12f, 1f) : new Color(0.35f, 0.9f, 1f, 1f));
				component.material = val3;
			}
			Rigidbody obj = val.AddComponent<Rigidbody>();
			obj.isKinematic = true;
			obj.useGravity = false;
			HandQuickbeltAdjustmentHandle handQuickbeltAdjustmentHandle = val.AddComponent<HandQuickbeltAdjustmentHandle>();
			handQuickbeltAdjustmentHandle.Configure(root, isLeftHand);
			val.SetActive(false);
			return handQuickbeltAdjustmentHandle;
		}

		private void CreateHandSlots(Transform root, List<FVRQuickBeltSlot> handSlots, FVRQuickBeltSlot template, int large, int medium, int small)
		{
			FVRPhysicalObjectSize[] array = (FVRPhysicalObjectSize[])(object)new FVRPhysicalObjectSize[3]
			{
				(FVRPhysicalObjectSize)2,
				(FVRPhysicalObjectSize)1,
				default(FVRPhysicalObjectSize)
			};
			int[] array2 = new int[3] { large, medium, small };
			int num = 0;
			for (int i = 0; i < array.Length; i++)
			{
				int num2 = 0;
				while (num2 < array2[i])
				{
					FVRQuickBeltSlot val = CreateSlot(root, template, array[i], num);
					if ((Object)(object)val != (Object)null)
					{
						handSlots.Add(val);
					}
					num2++;
					num++;
				}
			}
		}

		private FVRQuickBeltSlot CreateSlot(Transform root, FVRQuickBeltSlot template, FVRPhysicalObjectSize size, int index)
		{
			//IL_0019: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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)
			GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject);
			val.SetActive(false);
			((Object)val).name = $"HQB_{size}_{index + 1:00}";
			val.transform.SetParent(root, false);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			val.transform.localScale = Vector3.one;
			FVRQuickBeltSlot component = val.GetComponent<FVRQuickBeltSlot>();
			if ((Object)(object)component == (Object)null || !BuildLocalGeometry(component, template))
			{
				Plugin.Logger.LogError((object)$"Could not create {((Object)val).name} from template {((Object)template).name}.");
				Object.Destroy((Object)(object)val);
				return null;
			}
			component.SizeLimit = size;
			component.Shape = (QuickbeltSlotShape)0;
			component.Type = (QuickbeltSlotType)0;
			component.IsPlayer = true;
			component.IsSelectable = true;
			component.CurObject = null;
			component.HeldObject = null;
			component.IsKeepingTrackWithHead = false;
			component.IsHovered = false;
			val.AddComponent<HandQuickbeltSlotMarker>();
			val.AddComponent<HandQuickbeltMiniaturizer>();
			val.SetActive(true);
			_body.QBSlots_Internal.Add(component);
			_slots.Add(component);
			return component;
		}

		private static bool BuildLocalGeometry(FVRQuickBeltSlot slot, FVRQuickBeltSlot template)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_00bc: 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_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Expected O, but got Unknown
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)template == (Object)null || (Object)(object)template.HoverGeo == (Object)null)
			{
				return false;
			}
			Renderer[] componentsInChildren = ((Component)slot).GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].enabled = false;
			}
			for (int num = ((Component)slot).transform.childCount - 1; num >= 0; num--)
			{
				Object.Destroy((Object)(object)((Component)((Component)slot).transform.GetChild(num)).gameObject);
			}
			GameObject val = new GameObject("HQB_QuickbeltRoot");
			val.transform.SetParent(((Component)slot).transform, false);
			GameObject val2 = Object.Instantiate<GameObject>(template.HoverGeo);
			((Object)val2).name = "HQB_HoverGeo";
			val2.transform.SetParent(val.transform, false);
			val2.transform.localPosition = Vector3.zero;
			val2.transform.localRotation = Quaternion.identity;
			Transform root = (((Object)(object)template.QuickbeltRoot != (Object)null) ? template.QuickbeltRoot : template.HoverGeo.transform.parent);
			Transform val3 = FindBaseSphere(template, root);
			GameObject val4 = Object.Instantiate<GameObject>(((Object)(object)val3 != (Object)null) ? ((Component)val3).gameObject : template.HoverGeo);
			((Object)val4).name = "HQB_BaseSphere";
			val4.transform.SetParent(val.transform, false);
			val4.transform.localPosition = Vector3.zero;
			val4.transform.localRotation = Quaternion.identity;
			val4.SetActive(true);
			GameObject val5 = new GameObject("HQB_PoseOverride");
			val5.transform.SetParent(val.transform, false);
			Renderer val6 = FindRenderer(val2.transform);
			Renderer val7 = FindRenderer(val4.transform);
			if ((Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				return false;
			}
			slot.QuickbeltRoot = val.transform;
			slot.HoverGeo = val2;
			slot.PoseOverride = val5.transform;
			slot.RectBounds = val4.transform;
			slot.m_hoverGeoRend = val6;
			val6.enabled = true;
			val7.enabled = true;
			val2.SetActive(false);
			slot.SetBaseRotation(Quaternion.identity);
			ApplyGeometryScale(slot);
			if ((Object)(object)val3 == (Object)null)
			{
				Plugin.Logger.LogWarning((object)$"{((Object)slot).name} uses a hover-material clone as its fallback base sphere.");
			}
			return true;
		}

		private static Transform FindBaseSphere(FVRQuickBeltSlot template, Transform root)
		{
			if ((Object)(object)template == (Object)null || (Object)(object)template.HoverGeo == (Object)null || (Object)(object)root == (Object)null)
			{
				return null;
			}
			Renderer val = FindRenderer(template.HoverGeo.transform);
			MeshFilter val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<MeshFilter>() : null);
			Renderer val3 = null;
			Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val4 in componentsInChildren)
			{
				if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val4 == (Object)(object)val) && !((Component)val4).transform.IsChildOf(template.HoverGeo.transform))
				{
					if ((Object)(object)val3 == (Object)null)
					{
						val3 = val4;
					}
					MeshFilter component = ((Component)val4).GetComponent<MeshFilter>();
					if ((Object)(object)val2 != (Object)null && (Object)(object)component != (Object)null && (Object)(object)component.sharedMesh == (Object)(object)val2.sharedMesh)
					{
						return ((Component)val4).transform;
					}
				}
			}
			if (!((Object)(object)val3 != (Object)null))
			{
				return null;
			}
			return ((Component)val3).transform;
		}

		private static Renderer FindRenderer(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			Renderer component = ((Component)root).GetComponent<Renderer>();
			if (!((Object)(object)component != (Object)null))
			{
				return ((Component)root).GetComponentInChildren<Renderer>(true);
			}
			return component;
		}

		private void ApplyLayout()
		{
			//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_004c: 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_0056: 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_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)
			if (!((Object)(object)_leftRoot == (Object)null) && !((Object)(object)_rightRoot == (Object)null))
			{
				_leftRoot.transform.localPosition = Plugin.MirrorPosition(Plugin.AnchorPosition.Value);
				_leftRoot.transform.localRotation = Plugin.MirrorRotation(Quaternion.Euler(Plugin.AnchorRotation.Value));
				_rightRoot.transform.localPosition = Plugin.AnchorPosition.Value;
				_rightRoot.transform.localRotation = Quaternion.Euler(Plugin.AnchorRotation.Value);
				ArrangeSlots(_leftSlots);
				ArrangeSlots(_rightSlots);
				SetHandleVisible(_leftHandle);
				SetHandleVisible(_rightHandle);
			}
		}

		private static void ArrangeSlots(List<FVRQuickBeltSlot> slots)
		{
			//IL_00a3: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Max(1, Plugin.GridColumns.Value);
			float num2 = (float)Plugin.SlotSpacingMillimeters.Value * 0.001f;
			for (int i = 0; i < slots.Count; i++)
			{
				FVRQuickBeltSlot val = slots[i];
				if (!((Object)(object)val == (Object)null))
				{
					int num3 = i / num;
					int num4 = i % num;
					int num5 = Mathf.Min(num, slots.Count - num3 * num);
					float num6 = ((float)num4 - (float)(num5 - 1) * 0.5f) * num2;
					float num7 = (float)(-num3) * num2;
					Transform parent = ((Component)val).transform.parent;
					((Component)val).transform.localPosition = (Vector3)(((Object)(object)parent != (Object)null) ? parent.InverseTransformVector(parent.right * num6 + parent.forward * num7) : new Vector3(num6, 0f, num7));
					ApplyGeometryScale(val);
				}
			}
		}

		private static void SetHandleVisible(HandQuickbeltAdjustmentHandle handle)
		{
			if (!((Object)(object)handle == (Object)null))
			{
				bool value = Plugin.ShowAdjustmentHandles.Value;
				if (!value && ((FVRInteractiveObject)handle).IsHeld)
				{
					((FVRInteractiveObject)handle).ForceBreakInteraction();
				}
				if (((Component)handle).gameObject.activeSelf != value)
				{
					((Component)handle).gameObject.SetActive(value);
				}
			}
		}

		private static void ApplyGeometryScale(FVRQuickBeltSlot slot)
		{
			//IL_006d: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
			float diameter = Mathf.Max(0.001f, Mathf.Abs((float)Plugin.SlotDiameterMillimeters.Value * 0.001f));
			if ((Object)(object)slot.HoverGeo != (Object)null)
			{
				SetWorldDiameter(slot.HoverGeo.transform, diameter);
			}
			if ((Object)(object)slot.RectBounds != (Object)null && (Object)(object)slot.HoverGeo != (Object)null)
			{
				slot.RectBounds.position = slot.HoverGeo.transform.position;
				slot.RectBounds.rotation = slot.HoverGeo.transform.rotation;
				slot.RectBounds.localScale = slot.HoverGeo.transform.localScale;
			}
		}

		private static void SetWorldDiameter(Transform sphere, float diameter)
		{
			//IL_001b: 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)
			//IL_0020: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)sphere.parent != (Object)null) ? sphere.parent.lossyScale : Vector3.one);
			sphere.localScale = new Vector3(diameter / Mathf.Max(0.0001f, Mathf.Abs(val.x)), diameter / Mathf.Max(0.0001f, Mathf.Abs(val.y)), diameter / Mathf.Max(0.0001f, Mathf.Abs(val.z)));
		}

		private FVRQuickBeltSlot FindTemplate(FVRPlayerBody body)
		{
			if ((Object)(object)body != (Object)null && body.QBSlots_Internal != null)
			{
				for (int i = 0; i < body.QBSlots_Internal.Count; i++)
				{
					FVRQuickBeltSlot val = body.QBSlots_Internal[i];
					if (IsUsableTemplate(val) && (Object)(object)((Component)val).GetComponent<HandQuickbeltSlotMarker>() == (Object)null)
					{
						return val;
					}
				}
			}
			if ((Object)(object)ManagerSingleton<GM>.Instance == (Object)null || ManagerSingleton<GM>.Instance.QuickbeltConfigurations == null)
			{
				return null;
			}
			FVRQuickBeltSlot val2 = null;
			GameObject[] quickbeltConfigurations = ManagerSingleton<GM>.Instance.QuickbeltConfigurations;
			foreach (GameObject val3 in quickbeltConfigurations)
			{
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				FVRQuickBeltSlot[] componentsInChildren = val3.GetComponentsInChildren<FVRQuickBeltSlot>(true);
				foreach (FVRQuickBeltSlot val4 in componentsInChildren)
				{
					if (IsUsableTemplate(val4))
					{
						if ((Object)(object)val2 == (Object)null)
						{
							val2 = val4;
						}
						if (((Object)val4).name == "QuickBeltSlot_Harness")
						{
							return val4;
						}
					}
				}
			}
			return val2;
		}

		private static bool IsUsableTemplate(FVRQuickBeltSlot slot)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)slot == (Object)null || (int)slot.Shape != 0 || (Object)(object)slot.HoverGeo == (Object)null)
			{
				return false;
			}
			Transform root = (((Object)(object)slot.QuickbeltRoot != (Object)null) ? slot.QuickbeltRoot : slot.HoverGeo.transform.parent);
			return (Object)(object)FindBaseSphere(slot, root) != (Object)null;
		}

		private void RemoveSlots(bool dropContents)
		{
			for (int num = _slots.Count - 1; num >= 0; num--)
			{
				FVRQuickBeltSlot val = _slots[num];
				if (!((Object)(object)val == (Object)null))
				{
					val.IsSelectable = false;
					HandQuickbeltMiniaturizer component = ((Component)val).GetComponent<HandQuickbeltMiniaturizer>();
					if ((Object)(object)component != (Object)null)
					{
						component.Restore();
					}
					if (dropContents && (Object)(object)val.CurObject != (Object)null)
					{
						val.CurObject.ClearQuickbeltState();
					}
					if ((Object)(object)_body != (Object)null && _body.QBSlots_Internal != null)
					{
						_body.QBSlots_Internal.Remove(val);
					}
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
			}
			_slots.Clear();
			_leftSlots.Clear();
			_rightSlots.Clear();
			_leftHandle = null;
			_rightHandle = null;
			DestroyRoot(ref _leftRoot);
			DestroyRoot(ref _rightRoot);
		}

		private static void DestroyRoot(ref GameObject root)
		{
			if ((Object)(object)root != (Object)null)
			{
				Object.Destroy((Object)(object)root);
				root = null;
			}
		}
	}
	internal sealed class HandQuickbeltSlotMarker : MonoBehaviour
	{
	}
	internal sealed class HandQuickbeltAdjustmentHandle : FVRInteractiveObject
	{
		private Transform _anchor;

		private bool _isLeftHand;

		private Vector3 _positionOffset;

		private Quaternion _rotationOffset;

		internal void Configure(Transform anchor, bool isLeftHand)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			_anchor = anchor;
			_isLeftHand = isLeftHand;
			base.ControlType = (FVRInteractionControlType)0;
			base.PoseOverride = ((Component)this).transform;
			base.EndInteractionIfDistant = false;
		}

		public override bool IsDistantGrabbable()
		{
			return false;
		}

		public override void BeginInteraction(FVRViveHand hand)
		{
			//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_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)
			//IL_0029: 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_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_0044: 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)
			((FVRInteractiveObject)this).BeginInteraction(hand);
			if ((Object)(object)_anchor != (Object)null)
			{
				Quaternion val = Quaternion.Inverse(((FVRInteractiveObject)this).m_handRot);
				_positionOffset = val * (_anchor.position - ((FVRInteractiveObject)this).m_handPos);
				_rotationOffset = val * _anchor.rotation;
			}
		}

		public override void UpdateInteraction(FVRViveHand hand)
		{
			//IL_001c: 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_0028: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			((FVRInteractiveObject)this).UpdateInteraction(hand);
			if ((Object)(object)_anchor != (Object)null)
			{
				_anchor.position = ((FVRInteractiveObject)this).m_handPos + ((FVRInteractiveObject)this).m_handRot * _positionOffset;
				_anchor.rotation = ((FVRInteractiveObject)this).m_handRot * _rotationOffset;
			}
		}

		public override void EndInteraction(FVRViveHand hand)
		{
			//IL_002c: 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)
			if ((Object)(object)_anchor != (Object)null && (Object)(object)Plugin.Instance != (Object)null)
			{
				Plugin.Instance.SaveAnchorPose(_isLeftHand, _anchor.localPosition, _anchor.localRotation);
			}
			((FVRInteractiveObject)this).EndInteraction(hand);
		}
	}
	internal sealed class HandQuickbeltMiniaturizer : MonoBehaviour
	{
		private readonly HashSet<GameObject> _knownPhysicalObjects = new HashSet<GameObject>();

		private FVRQuickBeltSlot _slot;

		private FVRPhysicalObject _item;

		private Vector3 _originalScale;

		private Vector3 _storedScale;

		private float _scaleFactor = 1f;

		private float _targetSize;

		private int _knownTransformCount;

		private void Awake()
		{
			_slot = ((Component)this).GetComponent<FVRQuickBeltSlot>();
		}

		private void Update()
		{
			FVRPhysicalObject val = (FVRPhysicalObject)((Plugin.MiniaturizeStoredObjects.Value && (Object)(object)_slot != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val != (Object)(object)_item)
			{
				Restore();
				if ((Object)(object)val != (Object)null)
				{
					Track(val);
				}
			}
			if (!((Object)(object)_item == (Object)null))
			{
				float num = TargetSizeMeters();
				if (!Mathf.Approximately(num, _targetSize))
				{
					RestoreScale();
					Fit(num);
				}
				if (((FVRInteractiveObject)_item).IsHeld)
				{
					RestoreScale();
					return;
				}
				RefitAfterHierarchyChange();
				ApplyScale();
			}
		}

		private void OnDestroy()
		{
			Restore();
		}

		internal void Restore()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			RestoreScale();
			_item = null;
			_storedScale = Vector3.zero;
			_scaleFactor = 1f;
			_targetSize = 0f;
			_knownTransformCount = 0;
			_knownPhysicalObjects.Clear();
		}

		internal void RestoreBeforeRemoval(FVRPhysicalObject physicalObject)
		{
			if ((Object)(object)_item == (Object)(object)physicalObject)
			{
				Restore();
			}
		}

		private void Track(FVRPhysicalObject physicalObject)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			_item = physicalObject;
			_originalScale = ((Component)physicalObject).transform.localScale;
			RecordHierarchy();
			Fit(TargetSizeMeters());
		}

		private void Fit(float targetSize)
		{
			//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_0035: 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_003b: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			_targetSize = targetSize;
			_scaleFactor = 1f;
			_storedScale = _originalScale;
			if (TryGetColliderBounds(((Component)_item).gameObject, out var bounds))
			{
				Vector3 size = ((Bounds)(ref bounds)).size;
				float num = Mathf.Max(size.x, Mathf.Max(size.y, size.z));
				if (num > targetSize)
				{
					_scaleFactor = targetSize / num;
					_storedScale = _originalScale * _scaleFactor;
				}
			}
		}

		private void RefitAfterHierarchyChange()
		{
			//IL_0063: 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)
			if (((Component)_item).GetComponentsInChildren<Transform>(true).Length == _knownTransformCount)
			{
				return;
			}
			RestoreScale();
			FVRPhysicalObject[] componentsInChildren = ((Component)_item).GetComponentsInChildren<FVRPhysicalObject>(true);
			foreach (FVRPhysicalObject val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)_item && !_knownPhysicalObjects.Contains(((Component)val).gameObject))
				{
					Transform transform = ((Component)val).transform;
					transform.localScale *= _scaleFactor;
				}
			}
			RecordHierarchy();
			Fit(_targetSize);
		}

		private void RecordHierarchy()
		{
			_knownPhysicalObjects.Clear();
			_knownTransformCount = ((Component)_item).GetComponentsInChildren<Transform>(true).Length;
			FVRPhysicalObject[] componentsInChildren = ((Component)_item).GetComponentsInChildren<FVRPhysicalObject>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)componentsInChildren[i] != (Object)null)
				{
					_knownPhysicalObjects.Add(((Component)componentsInChildren[i]).gameObject);
				}
			}
		}

		private void RestoreScale()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_item != (Object)null)
			{
				((Component)_item).transform.localScale = _originalScale;
			}
		}

		private void ApplyScale()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_item != (Object)null && !((FVRInteractiveObject)_item).IsHeld)
			{
				((Component)_item).transform.localScale = _storedScale;
			}
		}

		private static float TargetSizeMeters()
		{
			float num = (float)Mathf.Abs(Plugin.SlotDiameterMillimeters.Value) * 0.001f;
			return Mathf.Max(0.001f, num * (float)Plugin.StoredSizePercent.Value * 0.01f);
		}

		private static bool TryGetColliderBounds(GameObject root, out Bounds bounds)
		{
			//IL_0001: 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_0044: 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)
			bounds = default(Bounds);
			bool flag = false;
			Collider[] componentsInChildren = root.GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && val.enabled && ((Component)val).gameObject.activeInHierarchy && !val.isTrigger)
				{
					if (!flag)
					{
						bounds = val.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(val.bounds);
					}
				}
			}
			return flag;
		}
	}
	[HarmonyPatch(typeof(FVRPlayerBody), "ConfigureQuickbelt")]
	internal static class ConfigureQuickbeltPatch
	{
		[HarmonyPostfix]
		private static void Postfix(FVRPlayerBody __instance)
		{
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				Plugin.Instance.RebuildAfterQuickbeltChange(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(FVRViveHand), "TestQuickBeltDistances")]
	internal static class HandQuickbeltInteractionPatch
	{
		[HarmonyPostfix]
		private static void Postfix(FVRViveHand __instance)
		{
			//IL_0085: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || (Object)(object)GM.CurrentPlayerBody == (Object)null || GM.CurrentPlayerBody.QBSlots_Internal == null)
			{
				return;
			}
			FVRInteractiveObject currentInteractable = __instance.CurrentInteractable;
			FVRPhysicalObject val = (FVRPhysicalObject)(object)((currentInteractable is FVRPhysicalObject) ? currentInteractable : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.QuickbeltSlot != (Object)null)
			{
				return;
			}
			FVRQuickBeltSlot val2 = null;
			float num = float.MaxValue;
			for (int i = 0; i < GM.CurrentPlayerBody.QBSlots_Internal.Count; i++)
			{
				FVRQuickBeltSlot val3 = GM.CurrentPlayerBody.QBSlots_Internal[i];
				if (CanStore(val3, val) && IntersectsSlot(val3, val))
				{
					Vector3 val4 = val3.HoverGeo.transform.position - ((Component)val).transform.position;
					float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						val2 = val3;
						num = sqrMagnitude;
					}
				}
			}
			if ((Object)(object)val2 != (Object)null)
			{
				__instance.CurrentHoveredQuickbeltSlot = val2;
				__instance.CurrentHoveredQuickbeltSlotDirty = val2;
			}
			else if (IsHandQuickbelt(__instance.CurrentHoveredQuickbeltSlot))
			{
				__instance.CurrentHoveredQuickbeltSlot = null;
				__instance.CurrentHoveredQuickbeltSlotDirty = null;
			}
		}

		private static bool CanStore(FVRQuickBeltSlot slot, FVRPhysicalObject physicalObject)
		{
			//IL_002d: 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_003b: 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)
			if (IsHandQuickbelt(slot) && slot.IsSelectable && (Object)(object)slot.CurObject == (Object)null && (Object)(object)slot.HeldObject == (Object)null && slot.SizeLimit >= physicalObject.Size)
			{
				return slot.Type == physicalObject.QBSlotType;
			}
			return false;
		}

		private static bool IsHandQuickbelt(FVRQuickBeltSlot slot)
		{
			if ((Object)(object)slot != (Object)null)
			{
				return (Object)(object)((Component)slot).GetComponent<HandQuickbeltSlotMarker>() != (Object)null;
			}
			return false;
		}

		private static bool IntersectsSlot(FVRQuickBeltSlot slot, FVRPhysicalObject physicalObject)
		{
			//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_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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)slot.HoverGeo == (Object)null)
			{
				return false;
			}
			Vector3 position = slot.HoverGeo.transform.position;
			Vector3 lossyScale = slot.HoverGeo.transform.lossyScale;
			float num = 0.5f * Mathf.Min(Mathf.Abs(lossyScale.x), Mathf.Min(Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z)));
			float num2 = num * num;
			Collider[] componentsInChildren = ((Component)physicalObject).GetComponentsInChildren<Collider>(true);
			bool flag = false;
			foreach (Collider val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && val.enabled && ((Component)val).gameObject.activeInHierarchy && !val.isTrigger)
				{
					flag = true;
					Bounds bounds = val.bounds;
					if (((Bounds)(ref bounds)).SqrDistance(position) <= num2)
					{
						return true;
					}
				}
			}
			if (flag)
			{
				return false;
			}
			Transform val2 = (((Object)(object)((FVRInteractiveObject)physicalObject).PoseOverride != (Object)null) ? ((FVRInteractiveObject)physicalObject).PoseOverride : ((Component)physicalObject).transform);
			Vector3 val3 = slot.HoverGeo.transform.InverseTransformPoint(val2.position);
			return ((Vector3)(ref val3)).magnitude < 0.5f;
		}
	}
	[HarmonyPatch]
	internal static class StoredObjectScalePatch
	{
		[HarmonyPatch(typeof(FVRPhysicalObject), "SetParentage")]
		[HarmonyPrefix]
		private static void BeforeSetParentage(FVRPhysicalObject __instance)
		{
			RestoreBeforeRemoval(__instance);
		}

		[HarmonyPatch(typeof(FVRPhysicalObject), "SetQuickBeltSlot")]
		[HarmonyPrefix]
		private static void BeforeClearQuickbelt(FVRPhysicalObject __instance, FVRQuickBeltSlot slot)
		{
			if ((Object)(object)slot == (Object)null)
			{
				RestoreBeforeRemoval(__instance);
			}
		}

		private static void RestoreBeforeRemoval(FVRPhysicalObject physicalObject)
		{
			if (!((Object)(object)physicalObject == (Object)null) && !((Object)(object)physicalObject.QuickbeltSlot == (Object)null))
			{
				HandQuickbeltMiniaturizer component = ((Component)physicalObject.QuickbeltSlot).GetComponent<HandQuickbeltMiniaturizer>();
				if ((Object)(object)component != (Object)null)
				{
					component.RestoreBeforeRemoval(physicalObject);
				}
			}
		}
	}
	[BepInProcess("h3vr.exe")]
	[BepInPlugin("quaternion.hqb", "Hand Quickbelts", "0.4.2")]
	public class Plugin : BaseUnityPlugin
	{
		internal static readonly Vector3 DefaultAnchorPosition = new Vector3(-1.4656025f, 0.07558223f, -0.8075327f);

		internal static readonly Vector3 DefaultAnchorRotation = new Vector3(-6.0018616f, 36.728462f, 174.04753f);

		private HandQuickbeltController _controller;

		private Harmony _harmony;

		private bool _resetting;

		public const string Id = "quaternion.hqb";

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		internal static ConfigEntry<int> LeftLargeSlots { get; private set; }

		internal static ConfigEntry<int> LeftMediumSlots { get; private set; }

		internal static ConfigEntry<int> LeftSmallSlots { get; private set; }

		internal static ConfigEntry<int> RightLargeSlots { get; private set; }

		internal static ConfigEntry<int> RightMediumSlots { get; private set; }

		internal static ConfigEntry<int> RightSmallSlots { get; private set; }

		internal static ConfigEntry<int> GridColumns { get; private set; }

		internal static ConfigEntry<int> SlotSpacingMillimeters { get; private set; }

		internal static ConfigEntry<int> SlotDiameterMillimeters { get; private set; }

		internal static ConfigEntry<Vector3> AnchorPosition { get; private set; }

		internal static ConfigEntry<Vector3> AnchorRotation { get; private set; }

		internal static ConfigEntry<bool> ShowAdjustmentHandles { get; private set; }

		internal static ConfigEntry<bool> ResetAllSettings { get; private set; }

		internal static ConfigEntry<bool> MiniaturizeStoredObjects { get; private set; }

		internal static ConfigEntry<int> StoredSizePercent { get; private set; }

		public static string Name => "Hand Quickbelts";

		public static string Version => "0.4.2";

		private void Awake()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			RegisterVectorConverter();
			BindConfig();
			_controller = new HandQuickbeltController();
			SubscribeToConfigChanges();
			_harmony = new Harmony("quaternion.hqb");
			_harmony.PatchAll();
			Logger.LogMessage((object)$"{Name} {Version} loaded.");
		}

		private void Update()
		{
			if (_controller != null)
			{
				_controller.Tick();
			}
		}

		private void OnDestroy()
		{
			if (_controller != null)
			{
				_controller.Dispose();
				_controller = null;
			}
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
				_harmony = null;
			}
			Instance = null;
		}

		private void BindConfig()
		{
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Expected O, but got Unknown
			LeftLargeSlots = BindSlotCount("Left Large Slots", 1, "Large quickbelt slots attached below the left hand.");
			LeftMediumSlots = BindSlotCount("Left Medium Slots", 0, "Medium quickbelt slots attached below the left hand.");
			LeftSmallSlots = BindSlotCount("Left Small Slots", 0, "Small quickbelt slots attached below the left hand.");
			RightLargeSlots = BindSlotCount("Right Large Slots", 1, "Large quickbelt slots attached below the right hand.");
			RightMediumSlots = BindSlotCount("Right Medium Slots", 0, "Medium quickbelt slots attached below the right hand.");
			RightSmallSlots = BindSlotCount("Right Small Slots", 0, "Small quickbelt slots attached below the right hand.");
			GridColumns = ((BaseUnityPlugin)this).Config.Bind<int>("Slots", "Grid Columns", 2, "Slots per row before the grid wraps toward the elbow.");
			SlotSpacingMillimeters = ((BaseUnityPlugin)this).Config.Bind<int>("Slots", "Slot Spacing (mm)", 120, "World-space center-to-center spacing on both grid axes.");
			SlotDiameterMillimeters = ((BaseUnityPlugin)this).Config.Bind<int>("Slots", "Slot Diameter (mm)", 100, "World-space diameter of each native sphere visual and interaction volume.");
			AnchorPosition = ((BaseUnityPlugin)this).Config.Bind<Vector3>("Placement", "Anchor Position (meters)", DefaultAnchorPosition, "Shared palm-local position. The left hand uses its mirrored pose.");
			AnchorRotation = ((BaseUnityPlugin)this).Config.Bind<Vector3>("Placement", "Anchor Rotation (degrees)", DefaultAnchorRotation, "Shared palm-local Euler rotation. The left hand uses its mirrored pose.");
			ShowAdjustmentHandles = ((BaseUnityPlugin)this).Config.Bind<bool>("Placement", "Show Adjustment Handles", false, "Show grabbable handles for moving and rotating the shared anchor pose.");
			ResetAllSettings = ((BaseUnityPlugin)this).Config.Bind<bool>("Placement", "Reset All Settings", false, "Restore every Hand Quickbelts setting to its default, then turn this toggle off.");
			MiniaturizeStoredObjects = ((BaseUnityPlugin)this).Config.Bind<bool>("Stored Objects", "Miniaturize Stored Objects", true, "Reduce stored items to fit and restore their original scale before removal.");
			StoredSizePercent = ((BaseUnityPlugin)this).Config.Bind<int>("Stored Objects", "Stored Size (% of Slot Diameter)", 80, new ConfigDescription("Maximum stored-object size as a percentage of the slot diameter. Objects are reduced to fit but never enlarged.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), new object[0]));
		}

		private ConfigEntry<int> BindSlotCount(string name, int defaultValue, string description)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			return ((BaseUnityPlugin)this).Config.Bind<int>("Slots", name, defaultValue, new ConfigDescription(description + " Changing a slot count drops items stored in hand slots.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), new object[0]));
		}

		private void SubscribeToConfigChanges()
		{
			ConfigEntry<int>[] array = new ConfigEntry<int>[6] { LeftLargeSlots, LeftMediumSlots, LeftSmallSlots, RightLargeSlots, RightMediumSlots, RightSmallSlots };
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SettingChanged += OnSlotCountChanged;
			}
			GridColumns.SettingChanged += OnLayoutChanged;
			SlotSpacingMillimeters.SettingChanged += OnLayoutChanged;
			SlotDiameterMillimeters.SettingChanged += OnLayoutChanged;
			AnchorPosition.SettingChanged += OnLayoutChanged;
			AnchorRotation.SettingChanged += OnLayoutChanged;
			ShowAdjustmentHandles.SettingChanged += OnLayoutChanged;
			ResetAllSettings.SettingChanged += OnResetAllSettingsChanged;
		}

		private void OnSlotCountChanged(object sender, EventArgs eventArgs)
		{
			if (_controller != null)
			{
				_controller.RequestRebuild();
			}
		}

		private void OnLayoutChanged(object sender, EventArgs eventArgs)
		{
			if (_controller != null)
			{
				_controller.RequestLayout();
			}
		}

		private void OnResetAllSettingsChanged(object sender, EventArgs eventArgs)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if (!_resetting && ResetAllSettings.Value)
			{
				_resetting = true;
				LeftLargeSlots.Value = 1;
				LeftMediumSlots.Value = 0;
				LeftSmallSlots.Value = 0;
				RightLargeSlots.Value = 1;
				RightMediumSlots.Value = 0;
				RightSmallSlots.Value = 0;
				GridColumns.Value = 2;
				SlotSpacingMillimeters.Value = 120;
				SlotDiameterMillimeters.Value = 100;
				AnchorPosition.Value = DefaultAnchorPosition;
				AnchorRotation.Value = DefaultAnchorRotation;
				ShowAdjustmentHandles.Value = false;
				MiniaturizeStoredObjects.Value = true;
				StoredSizePercent.Value = 80;
				ResetAllSettings.Value = false;
				((BaseUnityPlugin)this).Config.Save();
				_resetting = false;
				if (_controller != null)
				{
					_controller.RequestRebuild();
				}
				Logger.LogInfo((object)"Reset all settings to defaults.");
			}
		}

		internal void RebuildAfterQuickbeltChange(FVRPlayerBody body)
		{
			if (_controller != null)
			{
				_controller.RebuildAfterQuickbeltChange(body);
			}
		}

		internal void SaveAnchorPose(bool isLeftHand, Vector3 position, Quaternion rotation)
		{
			//IL_0006: 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_0003: 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_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_0010: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_003d: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			Vector3 value = (isLeftHand ? MirrorPosition(position) : position);
			Quaternion val = (isLeftHand ? MirrorRotation(rotation) : rotation);
			Vector3 eulerAngles = ((Quaternion)(ref val)).eulerAngles;
			AnchorPosition.Value = value;
			AnchorRotation.Value = new Vector3(NormalizeAngle(eulerAngles.x), NormalizeAngle(eulerAngles.y), NormalizeAngle(eulerAngles.z));
			((BaseUnityPlugin)this).Config.Save();
			Logger.LogInfo((object)string.Format("Saved shared anchor from the {0} handle: position {1}, rotation {2}.", isLeftHand ? "left" : "right", AnchorPosition.Value, AnchorRotation.Value));
		}

		internal static Vector3 MirrorPosition(Vector3 position)
		{
			//IL_0000: 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_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)
			return new Vector3(0f - position.x, position.y, position.z);
		}

		internal static Quaternion MirrorRotation(Quaternion rotation)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			return new Quaternion(rotation.x, 0f - rotation.y, 0f - rotation.z, rotation.w);
		}

		private static float NormalizeAngle(float angle)
		{
			if (!(angle > 180f))
			{
				return angle;
			}
			return angle - 360f;
		}

		private static void RegisterVectorConverter()
		{
			if (!TypeDescriptor.GetConverter(typeof(Vector3)).CanConvertFrom(typeof(string)))
			{
				TypeDescriptor.AddAttributes(typeof(Vector3), new TypeConverterAttribute(typeof(Vector3ConfigTypeConverter)));
			}
		}
	}
	public sealed class Vector3ConfigTypeConverter : TypeConverter
	{
		public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
		{
			if ((object)sourceType != typeof(string))
			{
				return base.CanConvertFrom(context, sourceType);
			}
			return true;
		}

		public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
		{
			if ((object)destinationType != typeof(string))
			{
				return base.CanConvertTo(context, destinationType);
			}
			return true;
		}

		public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (!(value is string text))
			{
				return base.ConvertFrom(context, culture, value);
			}
			string[] array = text.Trim().Trim('(', ')').Split(new char[1] { ',' });
			if (array.Length != 3)
			{
				throw new FormatException("Expected a vector in x, y, z format.");
			}
			return (object)new Vector3(float.Parse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture), float.Parse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture), float.Parse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture));
		}

		public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
		{
			//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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if ((object)destinationType == typeof(string) && value is Vector3 val)
			{
				return string.Format(CultureInfo.InvariantCulture, "{0:0.######}, {1:0.######}, {2:0.######}", new object[3] { val.x, val.y, val.z });
			}
			return base.ConvertTo(context, culture, value, destinationType);
		}
	}
}