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 _slots = new List(); private readonly List _leftSlots = new List(); private readonly List _rightSlots = new List(); 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(); 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(); 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(); obj.isKinematic = true; obj.useGravity = false; HandQuickbeltAdjustmentHandle handQuickbeltAdjustmentHandle = val.AddComponent(); handQuickbeltAdjustmentHandle.Configure(root, isLeftHand); val.SetActive(false); return handQuickbeltAdjustmentHandle; } private void CreateHandSlots(Transform root, List 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(((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(); 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(); val.AddComponent(); 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(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(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(((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() : null); Renderer val3 = null; Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren(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(); 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(); if (!((Object)(object)component != (Object)null)) { return ((Component)root).GetComponentInChildren(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 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() == (Object)null) { return val; } } } if ((Object)(object)ManagerSingleton.Instance == (Object)null || ManagerSingleton.Instance.QuickbeltConfigurations == null) { return null; } FVRQuickBeltSlot val2 = null; GameObject[] quickbeltConfigurations = ManagerSingleton.Instance.QuickbeltConfigurations; foreach (GameObject val3 in quickbeltConfigurations) { if ((Object)(object)val3 == (Object)null) { continue; } FVRQuickBeltSlot[] componentsInChildren = val3.GetComponentsInChildren(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(); 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 _knownPhysicalObjects = new HashSet(); 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(); } 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(true).Length == _knownTransformCount) { return; } RestoreScale(); FVRPhysicalObject[] componentsInChildren = ((Component)_item).GetComponentsInChildren(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(true).Length; FVRPhysicalObject[] componentsInChildren = ((Component)_item).GetComponentsInChildren(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(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() != (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(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(); 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 LeftLargeSlots { get; private set; } internal static ConfigEntry LeftMediumSlots { get; private set; } internal static ConfigEntry LeftSmallSlots { get; private set; } internal static ConfigEntry RightLargeSlots { get; private set; } internal static ConfigEntry RightMediumSlots { get; private set; } internal static ConfigEntry RightSmallSlots { get; private set; } internal static ConfigEntry GridColumns { get; private set; } internal static ConfigEntry SlotSpacingMillimeters { get; private set; } internal static ConfigEntry SlotDiameterMillimeters { get; private set; } internal static ConfigEntry AnchorPosition { get; private set; } internal static ConfigEntry AnchorRotation { get; private set; } internal static ConfigEntry ShowAdjustmentHandles { get; private set; } internal static ConfigEntry ResetAllSettings { get; private set; } internal static ConfigEntry MiniaturizeStoredObjects { get; private set; } internal static ConfigEntry 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("Slots", "Grid Columns", 2, "Slots per row before the grid wraps toward the elbow."); SlotSpacingMillimeters = ((BaseUnityPlugin)this).Config.Bind("Slots", "Slot Spacing (mm)", 120, "World-space center-to-center spacing on both grid axes."); SlotDiameterMillimeters = ((BaseUnityPlugin)this).Config.Bind("Slots", "Slot Diameter (mm)", 100, "World-space diameter of each native sphere visual and interaction volume."); AnchorPosition = ((BaseUnityPlugin)this).Config.Bind("Placement", "Anchor Position (meters)", DefaultAnchorPosition, "Shared palm-local position. The left hand uses its mirrored pose."); AnchorRotation = ((BaseUnityPlugin)this).Config.Bind("Placement", "Anchor Rotation (degrees)", DefaultAnchorRotation, "Shared palm-local Euler rotation. The left hand uses its mirrored pose."); ShowAdjustmentHandles = ((BaseUnityPlugin)this).Config.Bind("Placement", "Show Adjustment Handles", false, "Show grabbable handles for moving and rotating the shared anchor pose."); ResetAllSettings = ((BaseUnityPlugin)this).Config.Bind("Placement", "Reset All Settings", false, "Restore every Hand Quickbelts setting to its default, then turn this toggle off."); MiniaturizeStoredObjects = ((BaseUnityPlugin)this).Config.Bind("Stored Objects", "Miniaturize Stored Objects", true, "Reduce stored items to fit and restore their original scale before removal."); StoredSizePercent = ((BaseUnityPlugin)this).Config.Bind("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(1, 1000), new object[0])); } private ConfigEntry 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("Slots", name, defaultValue, new ConfigDescription(description + " Changing a slot count drops items stored in hand slots.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 10), new object[0])); } private void SubscribeToConfigChanges() { ConfigEntry[] array = new ConfigEntry[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); } } }