Decompiled source of ValheimHolster v1.0.4

ValheimHolster.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Padilha")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ValheimHolster")]
[assembly: AssemblyTitle("ValheimHolster")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimHolster
{
	internal struct ExtraEntry
	{
		public HolsterJoint Joint;

		public int Hash;

		public int Variant;

		public int Quality;
	}
	internal static class ExtraHolster
	{
		public const string ZdoKey = "ValheimHolster.Extra";

		private static float _timer;

		private static string _lastWritten;

		private static readonly List<ExtraEntry> _entries = new List<ExtraEntry>();

		private static readonly HashSet<HolsterJoint> _used = new HashSet<HolsterJoint>();

		private static readonly HashSet<int> _unplacedLogged = new HashSet<int>();

		public const string HideKey = "ValheimHolster.Hide";

		public const string QuiverKey = "ValheimHolster.Quiver";

		private static float _stateTimer;

		private static int _lastHide = -1;

		private static int _lastQuiver = int.MinValue;

		public static void MarkDirty()
		{
			_timer = 0f;
			_stateTimer = 0f;
		}

		public static void Tick()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				_lastWritten = null;
				_lastHide = -1;
				_lastQuiver = int.MinValue;
				return;
			}
			PublishState(localPlayer);
			_timer -= Time.deltaTime;
			if (_timer > 0f)
			{
				return;
			}
			_timer = 0.25f;
			ZNetView component = ((Component)localPlayer).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
			{
				return;
			}
			string text = ((HolsterConfig.Enabled.Value && HolsterConfig.ShowExtras.Value) ? Compute(localPlayer, preview: false) : "");
			if (!(text == _lastWritten))
			{
				_lastWritten = text;
				component.GetZDO().Set("ValheimHolster.Extra", text);
				if (HolsterConfig.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)("Extras publicados: " + Describe()));
				}
			}
		}

		private static void PublishState(Player player)
		{
			_stateTimer -= Time.deltaTime;
			if (_stateTimer > 0f)
			{
				return;
			}
			_stateTimer = 0.1f;
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
			{
				return;
			}
			ZDO zDO = component.GetZDO();
			int num = ((HolsterConfig.Enabled.Value && ShouldHide(player)) ? 1 : 0);
			if (num != _lastHide)
			{
				_lastHide = num;
				zDO.Set("ValheimHolster.Hide", num == 1);
			}
			int num2 = (HolsterConfig.Enabled.Value ? QuiverAmmo(player) : 0);
			if (num2 != _lastQuiver)
			{
				if (HolsterConfig.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)("Aljava: munição publicada = " + num2));
				}
				_lastQuiver = num2;
				zDO.Set("ValheimHolster.Quiver", num2);
			}
		}

		private static bool ShouldHide(Player p)
		{
			try
			{
				bool flag = ((Character)p).InBed() || p.IsSleeping();
				if (HolsterConfig.HideWhenSleeping.Value && flag)
				{
					return true;
				}
				if (HolsterConfig.HideWhenSitting.Value && !flag && (((Character)p).IsSitting() || ((Character)p).IsAttached()))
				{
					return true;
				}
				if (HolsterConfig.HideWhenSwimming.Value && ((Character)p).IsSwimming())
				{
					return true;
				}
				if (HolsterConfig.HideIndoors.Value && p.InShelter())
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		public static int QuiverAmmo(Player p)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Invalid comparison between Unknown and I4
			if (!HolsterConfig.QuiverEnabled.Value)
			{
				return 0;
			}
			Inventory inventory = ((Humanoid)p).GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			ItemData val = null;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem?.m_shared != null && (int)allItem.m_shared.m_itemType == 4 && !string.IsNullOrEmpty(allItem.m_shared.m_ammoType))
				{
					if (allItem.m_equipped)
					{
						val = allItem;
						break;
					}
					if (val == null && HolsterLogic.IsMarked(allItem))
					{
						val = allItem;
					}
				}
			}
			if (val == null)
			{
				return 0;
			}
			ItemData ammoItem = ((Humanoid)p).GetAmmoItem();
			if (ammoItem == null || ammoItem.m_shared.m_ammoType != val.m_shared.m_ammoType || !inventory.ContainsItem(ammoItem))
			{
				ammoItem = inventory.GetAmmoItem(val.m_shared.m_ammoType, (string)null);
			}
			int num = ((ammoItem != null) ? HolsterLogic.ItemHash(ammoItem) : 0);
			if (num == 0)
			{
				return -1;
			}
			return num;
		}

		public static string Compute(Player p, bool preview)
		{
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			_entries.Clear();
			_used.Clear();
			Inventory inventory = ((Humanoid)p).GetInventory();
			if (inventory == null)
			{
				return "";
			}
			ItemData val = (preview ? null : VanillaAccess.HiddenRightItem.Invoke((Humanoid)(object)p));
			ItemData val2 = (preview ? null : VanillaAccess.HiddenLeftItem.Invoke((Humanoid)(object)p));
			bool flag = preview && HolsterConfig.MenuFreeHands.Value && MenuHelper.InMainMenu;
			if (val != null)
			{
				_used.Add(HolsterJoints.VanillaJoint(val.m_shared, rightHand: true));
			}
			if (val2 != null)
			{
				_used.Add(HolsterJoints.VanillaJoint(val2.m_shared, rightHand: false));
			}
			int value = HolsterConfig.MaxExtras.Value;
			foreach (ItemData item in HolsterLogic.PlacementOrder(inventory))
			{
				if (_entries.Count >= value)
				{
					break;
				}
				if (!HolsterLogic.IsMarked(item) || !HolsterLogic.CanHolster(item) || (item.m_equipped && !flag) || item == val || item == val2)
				{
					continue;
				}
				int num = HolsterLogic.ItemHash(item);
				if (num == 0)
				{
					continue;
				}
				bool flag2 = false;
				foreach (HolsterJoint item2 in HolsterJoints.Candidates(item.m_shared))
				{
					if (!_used.Contains(item2))
					{
						_used.Add(item2);
						_entries.Add(new ExtraEntry
						{
							Joint = item2,
							Hash = num,
							Variant = item.m_variant,
							Quality = item.m_quality
						});
						flag2 = true;
						break;
					}
				}
				if (!flag2 && HolsterConfig.DebugLog.Value && !_unplacedLogged.Contains(num))
				{
					_unplacedLogged.Add(num);
					Plugin.Log.LogInfo((object)string.Format("Sem encaixe livre pra {0} (tipo={1}). Usados: {2}", item.m_shared.m_name, item.m_shared.m_itemType, string.Join(",", _used)));
				}
			}
			StringBuilder stringBuilder = new StringBuilder("1|");
			for (int i = 0; i < _entries.Count; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(';');
				}
				ExtraEntry extraEntry = _entries[i];
				stringBuilder.Append((int)extraEntry.Joint).Append(':').Append(extraEntry.Hash)
					.Append(':')
					.Append(extraEntry.Variant)
					.Append(':')
					.Append(extraEntry.Quality);
			}
			return stringBuilder.ToString();
		}

		private static string Describe()
		{
			if (_entries.Count == 0)
			{
				return "(nenhuma)";
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (ExtraEntry entry in _entries)
			{
				GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(entry.Hash) : null);
				stringBuilder.Append(((Object)(object)val != (Object)null) ? ((Object)val).name : entry.Hash.ToString()).Append('@').Append(entry.Joint)
					.Append(' ');
			}
			return stringBuilder.ToString();
		}

		public static void Parse(string data, List<ExtraEntry> into)
		{
			into.Clear();
			if (string.IsNullOrEmpty(data) || !data.StartsWith("1|"))
			{
				return;
			}
			string text = data.Substring(2);
			if (text.Length == 0)
			{
				return;
			}
			string[] array = text.Split(';');
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(':');
				if (array2.Length >= 4 && int.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
				{
					int.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3);
					int.TryParse(array2[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result4);
					if (result > 0 && result <= 10 && result2 != 0)
					{
						into.Add(new ExtraEntry
						{
							Joint = (HolsterJoint)result,
							Hash = result2,
							Variant = result3,
							Quality = result4
						});
					}
				}
			}
		}
	}
	public class ExtraHolsterVisual : MonoBehaviour
	{
		private VisEquipment _vis;

		private ZNetView _nview;

		private string _last;

		private int _lastRevision = -1;

		private float _timer;

		private readonly List<ExtraEntry> _entries = new List<ExtraEntry>();

		private readonly List<GameObject> _instances = new List<GameObject>();

		private Player _player;

		private bool _handsFreed;

		private bool _hidden;

		private GameObject _quiver;

		private int _quiverHash;

		private int _quiverRevision = -1;

		private float _quiverTimer;

		private bool _wasHidden;

		private void Awake()
		{
			_vis = ((Component)this).GetComponent<VisEquipment>();
			_nview = ((Component)this).GetComponent<ZNetView>();
		}

		private void OnDestroy()
		{
			Clear();
			if ((Object)(object)_quiver != (Object)null)
			{
				Object.Destroy((Object)(object)_quiver);
			}
		}

		private void Update()
		{
			UpdateHidden();
			UpdateQuiver();
			_timer -= Time.deltaTime;
			if (_timer > 0f || (Object)(object)_vis == (Object)null)
			{
				return;
			}
			string text;
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				_timer = 0.5f;
				if ((Object)(object)_player == (Object)null)
				{
					_player = ((Component)this).GetComponent<Player>();
				}
				if ((Object)(object)_player == (Object)null)
				{
					return;
				}
				bool flag = HolsterConfig.Enabled.Value && HolsterConfig.ShowInMenu.Value;
				text = (flag ? ExtraHolster.Compute(_player, preview: true) : "");
				UpdateMenuHands(flag && HolsterConfig.MenuFreeHands.Value && MenuHelper.InMainMenu);
			}
			else
			{
				_timer = (_nview.IsOwner() ? 0.05f : 0.2f);
				text = (HolsterConfig.Enabled.Value ? _nview.GetZDO().GetString("ValheimHolster.Extra", "") : "");
			}
			bool flag2 = false;
			foreach (GameObject instance in _instances)
			{
				if ((Object)(object)instance == (Object)null)
				{
					flag2 = true;
					break;
				}
			}
			if (!(text == _last) || _lastRevision != HolsterConfig.VisualRevision || flag2)
			{
				_last = text;
				_lastRevision = HolsterConfig.VisualRevision;
				Rebuild();
			}
		}

		private void UpdateHidden()
		{
			if ((Object)(object)_vis == (Object)null)
			{
				return;
			}
			bool flag = (Object)(object)_nview != (Object)null && _nview.IsValid();
			_hidden = flag && HolsterConfig.Enabled.Value && _nview.GetZDO().GetBool("ValheimHolster.Hide", false);
			if (!_hidden && !_wasHidden)
			{
				return;
			}
			_wasHidden = _hidden;
			bool show = !_hidden;
			foreach (GameObject instance in _instances)
			{
				SetShown(instance, show);
			}
			if (VanillaAccess.LeftBackInstance != null)
			{
				SetShown(VanillaAccess.LeftBackInstance.Invoke(_vis), show);
			}
			if (VanillaAccess.RightBackInstance != null)
			{
				SetShown(VanillaAccess.RightBackInstance.Invoke(_vis), show);
			}
			SetShown(_quiver, show);
		}

		private static void SetShown(GameObject go, bool show)
		{
			if ((Object)(object)go != (Object)null && go.activeSelf != show)
			{
				go.SetActive(show);
			}
		}

		private void UpdateQuiver()
		{
			_quiverTimer -= Time.deltaTime;
			if (_quiverTimer > 0f || (Object)(object)_vis == (Object)null)
			{
				return;
			}
			int num;
			if ((Object)(object)_nview != (Object)null && _nview.IsValid())
			{
				_quiverTimer = 0.2f;
				num = ((HolsterConfig.Enabled.Value && HolsterConfig.QuiverEnabled.Value) ? _nview.GetZDO().GetInt("ValheimHolster.Quiver", 0) : 0);
			}
			else
			{
				_quiverTimer = 0.5f;
				if ((Object)(object)_player == (Object)null)
				{
					_player = ((Component)this).GetComponent<Player>();
				}
				num = (((Object)(object)_player != (Object)null && HolsterConfig.Enabled.Value && HolsterConfig.ShowInMenu.Value) ? ExtraHolster.QuiverAmmo(_player) : 0);
			}
			if (num != _quiverHash || _quiverRevision != HolsterConfig.VisualRevision || (num != 0 && !((Object)(object)_quiver != (Object)null)))
			{
				_quiverHash = num;
				_quiverRevision = HolsterConfig.VisualRevision;
				if ((Object)(object)_quiver != (Object)null)
				{
					Object.Destroy((Object)(object)_quiver);
				}
				_quiver = ((num != 0) ? Quiver.Build(_vis, num) : null);
				if ((Object)(object)_quiver != (Object)null && _hidden)
				{
					_quiver.SetActive(false);
				}
			}
		}

		private void UpdateMenuHands(bool free)
		{
			if (free)
			{
				_vis.SetRightItem(0, 0);
				_vis.SetLeftItem(0, 0, 0);
				_handsFreed = true;
			}
			else if (_handsFreed)
			{
				_handsFreed = false;
				VanillaAccess.SetupVisEquipment((Humanoid)(object)_player);
			}
		}

		private void Clear()
		{
			foreach (GameObject instance in _instances)
			{
				if ((Object)(object)instance != (Object)null)
				{
					Object.Destroy((Object)(object)instance);
				}
			}
			_instances.Clear();
		}

		private void Rebuild()
		{
			Clear();
			ExtraHolster.Parse(_last, _entries);
			if (_entries.Count == 0 || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			foreach (ExtraEntry entry in _entries)
			{
				Transform val = HolsterJoints.Resolve(_vis, entry.Joint);
				if ((Object)(object)val == (Object)null)
				{
					if (HolsterConfig.DebugLog.Value)
					{
						Plugin.Log.LogWarning((object)$"Encaixe {entry.Joint} não existe neste personagem");
					}
					continue;
				}
				GameObject val2 = VanillaAccess.AttachItem(_vis, entry.Hash, entry.Variant, entry.Quality, val);
				if ((Object)(object)val2 == (Object)null)
				{
					if (HolsterConfig.DebugLog.Value)
					{
						Plugin.Log.LogWarning((object)$"Falha ao desenhar {entry.Hash} em {entry.Joint}");
					}
					continue;
				}
				if (entry.Joint == HolsterJoint.HipRight || entry.Joint == HolsterJoint.HipLeft)
				{
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(entry.Hash);
					HolsterLogic.ApplyHipOffset(s: (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null)?.m_itemData.m_shared, t: val2.transform, left: entry.Joint == HolsterJoint.HipLeft, character: ((Component)_vis).transform);
				}
				val2.AddComponent<MotionTween>().Init(entry.Hash, Motion.Kind.Body);
				if (_hidden)
				{
					val2.SetActive(false);
				}
				_instances.Add(val2);
			}
		}
	}
	internal static class MenuHelper
	{
		public static bool InMainMenu
		{
			get
			{
				if ((Object)(object)FejdStartup.instance != (Object)null)
				{
					return (Object)(object)Player.m_localPlayer == (Object)null;
				}
				return false;
			}
		}
	}
	public enum TextLanguage
	{
		Auto,
		English,
		Portuguese
	}
	public static class HolsterConfig
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<TextLanguage> Language;

		public static ConfigEntry<bool> DebugLog;

		public static ConfigEntry<KeyCode> MarkKey;

		public static ConfigEntry<bool> OnlyMarked;

		public static ConfigEntry<bool> HolsterOnSwap;

		public static ConfigEntry<bool> ShowExtras;

		public static ConfigEntry<int> MaxExtras;

		public static ConfigEntry<bool> CrossBigWeapons;

		public static ConfigEntry<bool> HolsterTools;

		public static ConfigEntry<bool> ShowTooltip;

		public static ConfigEntry<bool> SmoothMotion;

		public static ConfigEntry<float> MotionDuration;

		public static ConfigEntry<bool> HideWhenSitting;

		public static ConfigEntry<bool> HideWhenSleeping;

		public static ConfigEntry<bool> HideWhenSwimming;

		public static ConfigEntry<bool> HideIndoors;

		public static ConfigEntry<bool> SwapWithHideKey;

		public static ConfigEntry<bool> DoubleTapEmpty;

		public static ConfigEntry<float> DoubleTapWindow;

		public static ConfigEntry<bool> WheelEnabled;

		public static ConfigEntry<float> WheelHoldTime;

		public static ConfigEntry<bool> WheelOnlyMarked;

		public static ConfigEntry<bool> WheelGamepad;

		public static ConfigEntry<bool> OneHandOnHip;

		public static ConfigEntry<bool> UseLeftHip;

		public static ConfigEntry<float> HipTiltBack;

		public static ConfigEntry<float> HipRollOut;

		public static ConfigEntry<float> HipUp;

		public static ConfigEntry<float> HipForward;

		public static ConfigEntry<float> HipInward;

		public static ConfigEntry<bool> AxeHeadUp;

		public static ConfigEntry<float> AxeTilt;

		public static ConfigEntry<float> AxeUp;

		public static ConfigEntry<float> KnifeTilt;

		public static ConfigEntry<float> KnifeRoll;

		public static ConfigEntry<float> KnifeInward;

		public static ConfigEntry<float> KnifeUp;

		public static ConfigEntry<float> KnifeForward;

		public static ConfigEntry<Vector3> HipPositionOffset;

		public static ConfigEntry<Vector3> HipRotationOffset;

		public static ConfigEntry<bool> AutoEquipShield;

		public static ConfigEntry<bool> NoShieldWithAxe;

		public static ConfigEntry<bool> AutoUnequipShield;

		public static ConfigEntry<bool> LockHotbar;

		public static ConfigEntry<bool> ShowInMenu;

		public static ConfigEntry<bool> MenuFreeHands;

		public static ConfigEntry<bool> KeepLoaded;

		public static ConfigEntry<bool> ReloadWhileRunning;

		public static ConfigEntry<bool> ReloadNeedsAmmo;

		public static ConfigEntry<float> ReloadSpeed;

		public static ConfigEntry<bool> QuiverEnabled;

		public static ConfigEntry<int> QuiverArrows;

		public static ConfigEntry<Vector3> QuiverPosition;

		public static ConfigEntry<Vector3> QuiverRotation;

		public static ConfigEntry<float> QuiverScale;

		private static ConfigFile _cfg;

		private static Dictionary<string, Dictionary<string, string>> _oldValues;

		private static readonly List<ConfigDefinition> _migrated = new List<ConfigDefinition>();

		public static int VisualRevision { get; private set; }

		public static void Bind(ConfigFile cfg)
		{
			//IL_075f: Unknown result type (might be due to invalid IL or missing references)
			//IL_078d: Unknown result type (might be due to invalid IL or missing references)
			//IL_09c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_09f8: Unknown result type (might be due to invalid IL or missing references)
			_cfg = cfg;
			_oldValues = ReadFile(cfg.ConfigFilePath);
			Enabled = B("1 - General", "Enabled", "1 - Geral", "Ativado", def: true, "Turns the mod on/off.", "Liga/desliga o mod.");
			Language = B("1 - General", "Language", null, null, TextLanguage.Auto, "Language of the in-game texts (messages, tooltip, wheel). Auto = follows the game language.", "Idioma dos textos do jogo (mensagens, tooltip, roda). Auto = segue o idioma do jogo.");
			DebugLog = B("1 - General", "Debug log", "1 - Geral", "Log detalhado", def: false, "Writes what the mod is doing (marking, attach points) to LogOutput.log. Useful for bug reports.", "Escreve no LogOutput.log o que o mod está fazendo (marcação, encaixes). Útil pra reportar problemas.");
			MarkKey = B<KeyCode>("2 - Body", "Mark key", "2 - Corpo", "Tecla marcar", (KeyCode)104, "With the inventory open, hover a weapon and press this key to mark/unmark it. Marked weapons stay on your body and show up in the wheel.", "Com o inventário aberto, passe o mouse numa arma e aperte essa tecla pra marcar/desmarcar. Armas marcadas ficam no corpo e entram na roda.");
			OnlyMarked = B("2 - Body", "Only marked weapons on body", "2 - Corpo", "So armas marcadas ficam no corpo", def: true, "On: only marked weapons hang on your body; the rest just leave your hands. Off: any swapped weapon stays on the body.", "Ligado: só armas marcadas ficam penduradas no corpo; as outras simplesmente saem da mão. Desligado: qualquer arma trocada fica no corpo.");
			HolsterOnSwap = B("2 - Body", "Holster on swap", "2 - Corpo", "Guardar ao trocar de arma", def: true, "When you equip another weapon, the one in your hand goes to your body instead of vanishing.", "Ao equipar outra arma, a que estava na mão vai pro corpo em vez de sumir.");
			ShowExtras = B("2 - Body", "Show all marked weapons", "2 - Corpo", "Mostrar todas as marcadas", def: true, "Shows every marked weapon on your body, not just the two the game keeps.", "Mostra no corpo todas as armas marcadas, não só as duas que o jogo guarda.");
			MaxExtras = B("2 - Body", "Max extra weapons", "2 - Corpo", "Maximo de armas extras", 10, "How many extra marked weapons can show on your body (one per free spot).", "Quantas armas marcadas extras podem aparecer no corpo (uma por encaixe livre).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10));
			CrossBigWeapons = B("2 - Body", "Cross big weapons", "2 - Corpo", "Cruzar armas grandes", def: true, "Two big weapons (staff, greatsword, atgeir, bow...) on the same spot are crossed in an X on your back.", "Duas armas grandes (cajado, espadão, atgeir, arco...) no mesmo lugar ficam cruzadas em X nas costas.");
			HolsterTools = B("2 - Body", "Tools on body", "2 - Corpo", "Ferramentas no corpo", def: false, "Tools (hammer, hoe, cultivator, pickaxe, fishing rod, torch) can also stay on your body. Off: tools never stay on the body.", "Ferramentas (martelo, enxada, cultivador, picareta, vara de pesca, tocha) também podem ficar no corpo. Desligado: ferramentas nunca ficam no corpo.");
			ShowTooltip = B("2 - Body", "Show in tooltip", "2 - Corpo", "Mostrar no tooltip", def: true, "Shows in the weapon tooltip whether it is marked.", "Mostra no tooltip da arma se ela está marcada.");
			SmoothMotion = B("2 - Body", "Smooth motion", "2 - Corpo", "Animacao suave", def: true, "Weapons slide from your hand to your body (and back), grow in when they come from the inventory and shrink out when they go back.", "A arma desliza da mão pro corpo (e do corpo pra mão), cresce quando sai do inventário e encolhe quando volta pra ele.");
			MotionDuration = B("2 - Body", "Motion duration", "2 - Corpo", "Duracao da animacao", 0.3f, "Seconds a weapon takes to go from your hand to your body.", "Segundos que a arma leva pra ir da mão pro corpo.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f));
			HideWhenSitting = B("2 - Body", "Hide when sitting", null, null, def: true, "Weapons on the body disappear while you sit (chair, bench, ground or ship).", "As armas do corpo somem enquanto você está sentado (cadeira, banco, chão ou barco).");
			HideWhenSleeping = B("2 - Body", "Hide when sleeping", null, null, def: true, "Weapons on the body disappear while you lie in bed.", "As armas do corpo somem enquanto você está deitado na cama.");
			HideWhenSwimming = B("2 - Body", "Hide when swimming", null, null, def: false, "Weapons on the body disappear while you swim.", "As armas do corpo somem enquanto você nada.");
			HideIndoors = B("2 - Body", "Hide indoors", null, null, def: false, "Weapons on the body disappear while you are under a roof (inside a house).", "As armas do corpo somem enquanto você está debaixo de um teto (dentro de casa).");
			SwapWithHideKey = B("3 - Hide key (R)", "Tap swaps weapon", "3 - Tecla R", "Toque troca de arma", def: true, "A tap on R swaps the weapon in your hand with the one you used before.", "Um toque no R troca a arma da mão pela que estava antes.");
			DoubleTapEmpty = B("3 - Hide key (R)", "Double tap empties hands", "3 - Tecla R", "Dois toques esvaziam a mao", def: true, "Two quick taps on R empty your hands (marked weapons go to your body). When on, a single tap waits a moment to see if a second one comes.", "Dois toques rápidos no R tiram tudo da mão (o que estiver marcado vai pro corpo). Ligado, o toque simples espera um instante pra ver se vem o segundo.");
			DoubleTapWindow = B("3 - Hide key (R)", "Double tap window", "3 - Tecla R", "Tempo entre os dois toques", 0.28f, "Seconds between the two taps.", "Segundos entre os dois toques.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.15f, 0.6f));
			WheelEnabled = B("3 - Hide key (R)", "Hold opens wheel", "3 - Tecla R", "Segurar abre a roda", def: true, "Holding R opens the weapon wheel: move the mouse sideways (or scroll) to spin, release to equip, right click cancels. With ValheimDualWield: left/right click picks the hand, middle click cancels.", "Segurar o R abre a roda de armas: mouse pros lados (ou scroll) gira, soltar equipa, botão direito cancela. Com o ValheimDualWield: botão esquerdo/direito escolhe a mão, o do meio cancela.");
			WheelHoldTime = B("3 - Hide key (R)", "Hold time", "3 - Tecla R", "Tempo segurando", 0.25f, "Seconds holding R until the wheel opens.", "Segundos segurando o R até a roda abrir.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f));
			WheelOnlyMarked = B("3 - Hide key (R)", "Wheel only marked weapons", "3 - Tecla R", "Roda so com armas marcadas", def: true, "On: the wheel shows marked weapons (and the ones on your body). Off: every weapon in the inventory.", "Ligado: a roda mostra as armas marcadas (e as que estão guardadas). Desligado: todas as armas do inventário.");
			WheelGamepad = B("3 - Hide key (R)", "Gamepad wheel", null, null, def: true, "Gamepad: hold the hide button to open the wheel, aim with the right stick, release to equip, B cancels.", "Controle: segure o botão de guardar pra abrir a roda, aponte com o analógico direito, solte pra equipar, B cancela.");
			OneHandOnHip = B("4 - Hip", "One-handed on hip", "4 - Quadril", "Arma de uma mao no quadril", def: true, "Swords, axes, maces and knives (not spears) sit on your hip instead of your back.", "Espadas, machados, maças e facas (lanças não) ficam na cintura em vez das costas.");
			UseLeftHip = B("4 - Hip", "Use both sides", "4 - Quadril", "Usar os dois lados", def: true, "The second marked one-handed weapon goes on the other hip.", "A segunda arma de uma mão marcada vai pro outro lado do quadril.");
			HipTiltBack = B("4 - Hip", "Tilt back", "4 - Quadril", "Inclinacao pra tras", 35f, "Tilt in degrees. Positive = tip back and handle forward; 0 = straight.", "Graus de inclinação. Positivo = ponta pra trás e cabo pra frente; 0 = reta.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-90f, 90f));
			HipRollOut = B("4 - Hip", "Roll out", "4 - Quadril", "Giro pra fora", 0f, "Sideways roll in degrees. Positive = tip away from the leg (mirrored on both sides); 0 = straight.", "Graus de giro lateral. Positivo = ponta se afasta da perna (espelhado nos dois lados); 0 = reta.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-45f, 45f));
			HipUp = B("4 - Hip", "Height", "4 - Quadril", "Altura", 0.08f, "Meters to raise (positive) or lower the hip weapon.", "Metros pra subir (positivo) ou descer a arma da cintura.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.3f, 0.3f));
			HipForward = B("4 - Hip", "Forward", "4 - Quadril", "Frente", 0.06f, "Meters to move the hip weapon forward (positive) or back.", "Metros pra levar a arma da cintura pra frente (positivo) ou pra trás.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.3f, 0.3f));
			HipInward = B("4 - Hip", "Closer to body", "4 - Quadril", "Aproximar do corpo", 0.05f, "Meters the hip weapon is pulled toward the body (positive) or pushed away.", "Metros que a arma da cintura é puxada pra perto do corpo (positivo) ou afastada.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.3f, 0.3f));
			AxeHeadUp = B("4 - Hip", "Axe and mace - head up", null, null, def: true, "Axes and maces hang head up, like through a belt loop. Off: same pose as swords.", "Machados e maças ficam com a cabeça pra cima, como num passador do cinto. Desligado: mesma posição das espadas.");
			AxeTilt = B("4 - Hip", "Axe and mace - tilt", null, null, 20f, "Tilt in degrees for head-up axes and maces. Positive = head forward, handle back.", "Inclinação dos machados e maças de cabeça pra cima. Positivo = cabeça pra frente, cabo pra trás.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-90f, 90f));
			AxeUp = B("4 - Hip", "Axe and mace - height", null, null, 0f, "Meters to raise (positive) or lower head-up axes and maces.", "Metros pra subir (positivo) ou descer os machados e maças.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.3f, 0.3f));
			KnifeTilt = B("4 - Hip", "Knife - tilt", "4 - Quadril", "Faca - inclinacao", 10f, "Tilt for knives only (positive = tip back).", "Inclinação só da faca (positivo = ponta pra trás).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-90f, 90f));
			KnifeRoll = B("4 - Hip", "Knife - roll out", "4 - Quadril", "Faca - giro pra fora", 0f, "Sideways roll for knives only (positive = tip away from the leg).", "Giro lateral só da faca (positivo = ponta se afasta da perna).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-45f, 45f));
			KnifeInward = B("4 - Hip", "Knife - closer to thigh", "4 - Quadril", "Faca - aproximar da coxa", 0.03f, "Meters the knife is pulled toward the leg.", "Metros que a faca é puxada pra perto da perna.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.3f, 0.3f));
			KnifeUp = B("4 - Hip", "Knife - height", "4 - Quadril", "Faca - altura", 0.06f, "Meters to raise (positive) or lower the knife.", "Metros pra subir (positivo) ou descer a faca.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.3f, 0.3f));
			KnifeForward = B("4 - Hip", "Knife - forward", "4 - Quadril", "Faca - frente", 0f, "Meters to move the knife forward (positive) or back.", "Metros pra levar a faca pra frente (positivo) ou pra trás.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.3f, 0.3f));
			HipPositionOffset = B<Vector3>("4 - Hip", "Position fine-tune", "4 - Quadril", "Ajuste de posicao", Vector3.zero, "Fine position tweak (the other side is mirrored).", "Ajuste fino da posição (o outro lado é espelhado).");
			HipRotationOffset = B<Vector3>("4 - Hip", "Rotation fine-tune", "4 - Quadril", "Ajuste de rotacao", Vector3.zero, "Fine rotation tweak, in degrees.", "Ajuste fino da rotação, em graus.");
			AutoEquipShield = B("5 - Shield", "Shield with one-handed weapon", "5 - Escudo", "Escudo junto com arma de uma mao", def: true, "When you take a one-handed weapon with an empty left hand, the strongest shield in your inventory comes along.", "Ao pegar uma arma de uma mão com a mão esquerda vazia, o escudo mais forte do inventário vem junto.");
			NoShieldWithAxe = B("5 - Shield", "Except with axe", "5 - Escudo", "Exceto com machado", def: true, "Axes don't pull the shield (so you can chop trees without the movement penalty).", "Machado não puxa o escudo (pra cortar árvore sem a penalidade de movimento).");
			AutoUnequipShield = B("5 - Shield", "Shield follows weapon", "5 - Escudo", "Escudo acompanha a arma", def: true, "When the one-handed weapon leaves your hand, the shield goes with it (to your back if marked).", "Quando a arma de uma mão sai da mão, o escudo sai junto (e vai pras costas se estiver marcado).");
			LockHotbar = B("6 - Hotbar", "Number only equips", "6 - Hotbar", "Numero so equipa", def: false, "Pressing the hotbar number of a weapon already in your hand doesn't take it out of your hand.", "Apertar o número da hotbar de uma arma que já está na mão não tira ela da mão.");
			ShowInMenu = B("7 - Menu", "Show weapons in menu", "7 - Menu", "Mostrar armas no menu", def: true, "Main menu characters (preview and the ValheimMenu campfire) show their marked weapons on the body.", "Os personagens do menu (preview e fogueira do ValheimMenu) aparecem com as armas marcadas no corpo.");
			MenuFreeHands = B("7 - Menu", "Free hands in menu", "7 - Menu", "Maos livres no menu", def: true, "In the menu, the equipped weapon leaves the hand: if marked, it shows on the body.", "No menu, a arma equipada sai da mão: se estiver marcada, aparece no corpo.");
			KeepLoaded = B("8 - Reload", "Stay loaded when holstered", "8 - Recarga", "Continua carregada ao guardar", def: true, "A crossbow (or any weapon that needs reloading) put away loaded stays loaded when it comes back to your hand.", "Besta (ou qualquer arma que precisa recarregar) guardada carregada continua carregada quando volta pra mão.");
			ReloadWhileRunning = B("8 - Reload", "Reload while running", "8 - Recarga", "Recarregar correndo", def: true, "You can run while reloading, without cancelling the reload or slowing down.", "Dá pra correr enquanto recarrega, sem cancelar a recarga e sem ficar andando devagar.");
			ReloadNeedsAmmo = B("8 - Reload", "Reload only with ammo", "8 - Recarga", "So recarrega com municao", def: true, "The crossbow only starts reloading if you have bolts (or its ammo) in the inventory.", "A besta só começa a recarregar se você tiver virote (ou a munição dela) no inventário.");
			ReloadSpeed = B("8 - Reload", "Reload speed", "8 - Recarga", "Velocidade de recarga", 1f, "Reload speed multiplier. 1 = normal, 2 = twice as fast, 0.5 = half.", "Multiplicador da velocidade de recarga. 1 = normal, 2 = duas vezes mais rápido, 0.5 = metade.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f));
			QuiverEnabled = B("9 - Quiver", "Show quiver", null, null, def: true, "A quiver shows on your back when you carry a marked (or equipped) bow or crossbow, with the arrows/bolts you have (empty if you have none).", "Uma aljava aparece nas costas quando você leva um arco ou besta marcado (ou na mão), com as flechas/virotes que você tem (vazia se não tiver nenhuma).");
			QuiverArrows = B("9 - Quiver", "Arrows shown", null, null, 6, "How many arrows stick out of the quiver.", "Quantas flechas aparecem saindo da aljava.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10));
			QuiverPosition = B<Vector3>("9 - Quiver", "Position", null, null, new Vector3(0.12f, 0.02f, -0.03f), "Quiver position relative to the upper back, in meters (x = right, y = up, z = forward).", "Posição da aljava nas costas, em metros (x = direita, y = cima, z = frente).");
			QuiverRotation = B<Vector3>("9 - Quiver", "Rotation", null, null, new Vector3(0f, 0f, -25f), "Quiver rotation in degrees (z = lean to the side).", "Rotação da aljava em graus (z = inclinação pro lado).");
			QuiverScale = B("9 - Quiver", "Size", null, null, 1f, "Quiver size multiplier.", "Multiplicador do tamanho da aljava.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f));
			DropMigrated();
			ConfigEntryBase[] array = (ConfigEntryBase[])(object)new ConfigEntryBase[30]
			{
				(ConfigEntryBase)Enabled,
				(ConfigEntryBase)OnlyMarked,
				(ConfigEntryBase)ShowExtras,
				(ConfigEntryBase)MaxExtras,
				(ConfigEntryBase)CrossBigWeapons,
				(ConfigEntryBase)HolsterTools,
				(ConfigEntryBase)OneHandOnHip,
				(ConfigEntryBase)UseLeftHip,
				(ConfigEntryBase)HipTiltBack,
				(ConfigEntryBase)HipRollOut,
				(ConfigEntryBase)HipUp,
				(ConfigEntryBase)HipForward,
				(ConfigEntryBase)HipInward,
				(ConfigEntryBase)AxeHeadUp,
				(ConfigEntryBase)AxeTilt,
				(ConfigEntryBase)AxeUp,
				(ConfigEntryBase)KnifeTilt,
				(ConfigEntryBase)KnifeRoll,
				(ConfigEntryBase)KnifeInward,
				(ConfigEntryBase)KnifeUp,
				(ConfigEntryBase)KnifeForward,
				(ConfigEntryBase)HipPositionOffset,
				(ConfigEntryBase)HipRotationOffset,
				(ConfigEntryBase)ShowInMenu,
				(ConfigEntryBase)MenuFreeHands,
				(ConfigEntryBase)QuiverEnabled,
				(ConfigEntryBase)QuiverArrows,
				(ConfigEntryBase)QuiverPosition,
				(ConfigEntryBase)QuiverRotation,
				(ConfigEntryBase)QuiverScale
			};
			for (int i = 0; i < array.Length; i++)
			{
				SubscribeChanged(array[i], Visual);
			}
			static void Visual()
			{
				VisualRevision++;
				VanillaAccess.RefreshAllVisuals();
				ExtraHolster.MarkDirty();
			}
		}

		private static void SubscribeChanged(ConfigEntryBase entry, Action action)
		{
			EventInfo eventInfo = ((object)entry).GetType().GetEvent("SettingChanged");
			if (!(eventInfo == null))
			{
				EventHandler handler = delegate
				{
					action();
				};
				eventInfo.AddEventHandler(entry, handler);
			}
		}

		private static ConfigEntry<T> B<T>(string section, string key, string oldSection, string oldKey, T def, string en, string pt, AcceptableValueBase range = null)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			ConfigEntry<T> val = _cfg.Bind<T>(section, key, def, new ConfigDescription(en + "\n\nPT-BR: " + pt, range, Array.Empty<object>()));
			if (!Has(section, key) && oldSection != null && TryOld(oldSection, oldKey, out var value))
			{
				try
				{
					((ConfigEntryBase)val).SetSerializedValue(value);
					_migrated.Add(new ConfigDefinition(oldSection, oldKey));
				}
				catch
				{
				}
			}
			return val;
		}

		private static bool Has(string section, string key)
		{
			if (_oldValues != null && _oldValues.TryGetValue(section, out var value))
			{
				return value.ContainsKey(key);
			}
			return false;
		}

		private static bool TryOld(string section, string key, out string value)
		{
			value = null;
			if (_oldValues != null && _oldValues.TryGetValue(section, out var value2))
			{
				return value2.TryGetValue(key, out value);
			}
			return false;
		}

		private static void DropMigrated()
		{
			if (_migrated.Count == 0)
			{
				return;
			}
			try
			{
				if (AccessTools.Property(typeof(ConfigFile), "OrphanedEntries")?.GetValue(_cfg) is Dictionary<ConfigDefinition, string> dictionary)
				{
					foreach (ConfigDefinition item in _migrated)
					{
						dictionary.Remove(item);
					}
				}
				_cfg.Save();
				Plugin.Log.LogInfo((object)$"Config: {_migrated.Count} opções migradas pros nomes novos.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Config: não deu pra limpar as opções antigas: " + ex.Message));
			}
		}

		private static Dictionary<string, Dictionary<string, string>> ReadFile(string path)
		{
			Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>();
			try
			{
				if (!File.Exists(path))
				{
					return dictionary;
				}
				string key = "";
				string[] array = File.ReadAllLines(path);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (text.Length == 0 || text.StartsWith("#"))
					{
						continue;
					}
					if (text.StartsWith("[") && text.EndsWith("]"))
					{
						key = text.Substring(1, text.Length - 2);
						continue;
					}
					int num = text.IndexOf('=');
					if (num > 0)
					{
						if (!dictionary.TryGetValue(key, out var value))
						{
							value = (dictionary[key] = new Dictionary<string, string>());
						}
						value[text.Substring(0, num).Trim()] = text.Substring(num + 1).Trim();
					}
				}
			}
			catch
			{
			}
			return dictionary;
		}
	}
	public enum HolsterJoint
	{
		None,
		HipRight,
		HipLeft,
		BackMelee,
		BackTwoHand,
		BackAtgeir,
		BackBow,
		BackShield,
		BackTwoHandCross,
		BackAtgeirCross,
		BackBowCross
	}
	internal static class HolsterJoints
	{
		private const string HipLeftName = "ValheimHolster_HipLeft";

		private const string TwoHandCrossName = "ValheimHolster_TwoHandCross";

		private const string AtgeirCrossName = "ValheimHolster_AtgeirCross";

		private const string BowCrossName = "ValheimHolster_BowCross";

		public const HolsterJoint MaxJoint = HolsterJoint.BackBowCross;

		private const float CrossBackOffset = 0.04f;

		public static bool IsDualWeapon(SharedData s)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			if (s != null && (int)s.m_itemType != 5)
			{
				return (int)AttachType(s) == 5;
			}
			return false;
		}

		public static bool IsStaff(SharedData s)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			if (s != null)
			{
				if ((int)s.m_skillType != 9)
				{
					return (int)s.m_skillType == 10;
				}
				return true;
			}
			return false;
		}

		public static ItemType AttachType(SharedData s)
		{
			//IL_0001: 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_0009: Unknown result type (might be due to invalid IL or missing references)
			if ((int)s.m_attachOverride == 0)
			{
				return s.m_itemType;
			}
			return s.m_attachOverride;
		}

		public static HolsterJoint VanillaJoint(SharedData s, bool rightHand)
		{
			//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_0033: 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_0047: Expected I4, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected I4, but got Unknown
			if (s == null)
			{
				return HolsterJoint.None;
			}
			if (HolsterConfig.OneHandOnHip.Value && HolsterLogic.GoesOnHip(s))
			{
				if (rightHand || !HolsterConfig.UseLeftHip.Value)
				{
					return HolsterJoint.HipRight;
				}
				return HolsterJoint.HipLeft;
			}
			ItemType val = AttachType(s);
			switch (val - 3)
			{
			default:
				switch (val - 14)
				{
				case 1:
					if (!rightHand)
					{
						return HolsterJoint.HipRight;
					}
					return HolsterJoint.BackMelee;
				case 0:
				case 8:
					return HolsterJoint.BackTwoHand;
				case 5:
					return HolsterJoint.HipRight;
				case 6:
					return HolsterJoint.BackAtgeir;
				default:
					return HolsterJoint.None;
				}
			case 0:
				return HolsterJoint.BackMelee;
			case 1:
				return HolsterJoint.BackBow;
			case 2:
				return HolsterJoint.BackShield;
			}
		}

		public static IEnumerable<HolsterJoint> Candidates(SharedData s)
		{
			bool cross = HolsterConfig.CrossBigWeapons.Value;
			if (IsDualWeapon(s))
			{
				yield return HolsterJoint.BackShield;
				yield break;
			}
			if (IsStaff(s))
			{
				yield return HolsterJoint.BackAtgeir;
				if (cross)
				{
					yield return HolsterJoint.BackAtgeirCross;
				}
				yield return HolsterJoint.BackTwoHand;
				if (cross)
				{
					yield return HolsterJoint.BackTwoHandCross;
				}
				yield return HolsterJoint.BackBow;
				if (cross)
				{
					yield return HolsterJoint.BackBowCross;
				}
				yield break;
			}
			HolsterJoint first = VanillaJoint(s, rightHand: true);
			if (first == HolsterJoint.None)
			{
				yield break;
			}
			yield return first;
			switch (first)
			{
			case HolsterJoint.HipRight:
				if (HolsterLogic.GoesOnHip(s))
				{
					if (HolsterConfig.UseLeftHip.Value)
					{
						yield return HolsterJoint.HipLeft;
					}
					yield return HolsterJoint.BackMelee;
				}
				break;
			case HolsterJoint.BackMelee:
				yield return HolsterJoint.BackAtgeir;
				break;
			case HolsterJoint.BackTwoHand:
				if (cross)
				{
					yield return HolsterJoint.BackTwoHandCross;
				}
				yield return HolsterJoint.BackAtgeir;
				if (cross)
				{
					yield return HolsterJoint.BackAtgeirCross;
				}
				break;
			case HolsterJoint.BackBow:
				if (cross)
				{
					yield return HolsterJoint.BackBowCross;
				}
				break;
			case HolsterJoint.BackAtgeir:
				if (cross)
				{
					yield return HolsterJoint.BackAtgeirCross;
				}
				yield return HolsterJoint.BackTwoHand;
				if (cross)
				{
					yield return HolsterJoint.BackTwoHandCross;
				}
				break;
			}
		}

		public static Transform Resolve(VisEquipment vis, HolsterJoint joint)
		{
			return (Transform)(joint switch
			{
				HolsterJoint.HipRight => vis.m_backTool, 
				HolsterJoint.HipLeft => GetOrCreateMirror(vis, vis.m_backTool, "ValheimHolster_HipLeft", 0f), 
				HolsterJoint.BackTwoHandCross => GetOrCreateMirror(vis, vis.m_backTwohandedMelee, "ValheimHolster_TwoHandCross", 0.04f), 
				HolsterJoint.BackAtgeirCross => GetOrCreateMirror(vis, vis.m_backAtgeir, "ValheimHolster_AtgeirCross", 0.04f), 
				HolsterJoint.BackBowCross => GetOrCreateMirror(vis, vis.m_backBow, "ValheimHolster_BowCross", 0.04f), 
				HolsterJoint.BackMelee => vis.m_backMelee, 
				HolsterJoint.BackTwoHand => vis.m_backTwohandedMelee, 
				HolsterJoint.BackAtgeir => vis.m_backAtgeir, 
				HolsterJoint.BackBow => vis.m_backBow, 
				HolsterJoint.BackShield => vis.m_backShield, 
				_ => null, 
			});
		}

		private static Transform GetOrCreateMirror(VisEquipment vis, Transform source, string name, float backOffset)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0072: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: 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_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null || (Object)(object)source.parent == (Object)null)
			{
				return null;
			}
			Transform parent = source.parent;
			Transform val = parent.Find(name);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			Vector3 val2 = parent.InverseTransformDirection(((Component)vis).transform.right);
			int num = 0;
			float num2 = Mathf.Abs(val2.x);
			if (Mathf.Abs(val2.y) > num2)
			{
				num = 1;
				num2 = Mathf.Abs(val2.y);
			}
			if (Mathf.Abs(val2.z) > num2)
			{
				num = 2;
			}
			Vector3 val3 = source.localPosition;
			Quaternion localRotation = source.localRotation;
			switch (num)
			{
			case 0:
				val3.x = 0f - val3.x;
				((Quaternion)(ref localRotation))..ctor(localRotation.x, 0f - localRotation.y, 0f - localRotation.z, localRotation.w);
				break;
			case 1:
				val3.y = 0f - val3.y;
				((Quaternion)(ref localRotation))..ctor(0f - localRotation.x, localRotation.y, 0f - localRotation.z, localRotation.w);
				break;
			default:
				val3.z = 0f - val3.z;
				((Quaternion)(ref localRotation))..ctor(0f - localRotation.x, 0f - localRotation.y, localRotation.z, localRotation.w);
				break;
			}
			if (backOffset != 0f)
			{
				val3 += parent.InverseTransformDirection(-((Component)vis).transform.forward) * backOffset / Mathf.Max(parent.lossyScale.x, 0.0001f);
			}
			Transform transform = new GameObject(name).transform;
			transform.SetParent(parent, false);
			transform.localPosition = val3;
			transform.localRotation = localRotation;
			transform.localScale = source.localScale;
			return transform;
		}
	}
	internal static class HolsterLogic
	{
		public static bool Busy;

		public static bool HideKeyThisFrame;

		public static int EquipDepth;

		public static bool ModCall;

		public static bool SuppressVanillaHide;

		public static ItemData LastRight;

		public static ItemData LastLeft;

		public const string DualWieldLeftKey = "morgnar.dualwield.lefthand";

		public const string DualWieldGuid = "morgnar.valheimdualwield";

		private static int _dualWield = -1;

		public const string CustomDataKey = "ValheimHolster.Marked";

		public static bool DualWieldInstalled
		{
			get
			{
				if (_dualWield < 0)
				{
					_dualWield = (Chainloader.PluginInfos.ContainsKey("morgnar.valheimdualwield") ? 1 : 0);
				}
				return _dualWield == 1;
			}
		}

		public static bool IsLocal(Humanoid h)
		{
			if ((Object)(object)h != (Object)null)
			{
				return (Object)(object)h == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

		public static bool IsActive(Humanoid h)
		{
			if (HolsterConfig.Enabled.Value)
			{
				return IsLocal(h);
			}
			return false;
		}

		public static bool IsTool(ItemData item)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			SharedData val = item?.m_shared;
			if (val == null)
			{
				return false;
			}
			ItemType itemType = val.m_itemType;
			if ((int)itemType == 15 || (int)itemType == 19)
			{
				return true;
			}
			if ((int)val.m_skillType != 12)
			{
				return (int)val.m_skillType == 104;
			}
			return true;
		}

		public static bool IsHandItem(ItemData item)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Invalid comparison between Unknown and I4
			//IL_001e: 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: Invalid comparison between Unknown and I4
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			//IL_0024: 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_0029: Invalid comparison between Unknown and I4
			SharedData val = item?.m_shared;
			if (val == null)
			{
				return false;
			}
			ItemType itemType = val.m_itemType;
			if ((int)itemType <= 15)
			{
				if (itemType - 3 <= 2 || itemType - 14 <= 1)
				{
					goto IL_0037;
				}
			}
			else if ((int)itemType == 19 || (int)itemType == 22)
			{
				goto IL_0037;
			}
			return false;
			IL_0037:
			return true;
		}

		public static bool CanHolster(ItemData item)
		{
			if (!IsHandItem(item))
			{
				return false;
			}
			if (IsTool(item))
			{
				return HolsterConfig.HolsterTools.Value;
			}
			if (HolsterConfig.OnlyMarked.Value && !IsMarked(item))
			{
				return false;
			}
			return true;
		}

		public static bool IsOneHandWeapon(ItemData item)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if (item?.m_shared != null && (int)item.m_shared.m_itemType == 3)
			{
				return !IsTool(item);
			}
			return false;
		}

		public static bool IsShield(ItemData item)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if (item?.m_shared != null)
			{
				return (int)item.m_shared.m_itemType == 5;
			}
			return false;
		}

		public static bool GoesOnHip(SharedData s)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			if (s != null && (int)s.m_itemType == 3 && (int)s.m_skillType != 5 && (int)s.m_skillType != 12)
			{
				return (int)s.m_skillType != 104;
			}
			return false;
		}

		public static bool StillHolsterable(Humanoid h, ItemData item)
		{
			if (item == null || item.m_equipped)
			{
				return false;
			}
			if (!CanHolster(item))
			{
				return false;
			}
			Inventory inventory = h.GetInventory();
			if (inventory != null)
			{
				return inventory.ContainsItem(item);
			}
			return false;
		}

		public static void RememberLast(Humanoid h, ItemData right, ItemData left)
		{
			if (IsLocal(h))
			{
				if (right != null && IsHandItem(right) && !IsTool(right))
				{
					LastRight = right;
				}
				if (left != null && IsHandItem(left) && !IsTool(left))
				{
					LastLeft = left;
				}
				else if (right != null && IsHandItem(right) && !IsTool(right))
				{
					LastLeft = null;
				}
			}
		}

		private static bool UsableLast(Humanoid h, ItemData item)
		{
			if (item == null || item.m_equipped)
			{
				return false;
			}
			Inventory inventory = h.GetInventory();
			if (inventory != null)
			{
				return inventory.ContainsItem(item);
			}
			return false;
		}

		public static bool SwapWithHolster(Humanoid h)
		{
			ItemData val = VanillaAccess.RightItem.Invoke(h);
			ItemData val2 = VanillaAccess.LeftItem.Invoke(h);
			ItemData val3 = VanillaAccess.HiddenRightItem.Invoke(h);
			ItemData val4 = VanillaAccess.HiddenLeftItem.Invoke(h);
			if (!StillHolsterable(h, val3))
			{
				val3 = null;
			}
			if (!StillHolsterable(h, val4))
			{
				val4 = null;
			}
			if (val3 == null && val4 == null)
			{
				val3 = (UsableLast(h, LastRight) ? LastRight : null);
				val4 = (UsableLast(h, LastLeft) ? LastLeft : null);
				if (val3 == null && val4 == null)
				{
					return false;
				}
			}
			Busy = true;
			try
			{
				if (val != null)
				{
					h.UnequipItem(val, false);
				}
				if (val2 != null)
				{
					h.UnequipItem(val2, false);
				}
				VanillaAccess.HiddenRightItem.Invoke(h) = null;
				VanillaAccess.HiddenLeftItem.Invoke(h) = null;
				if (val4 != null)
				{
					h.EquipItem(val4, true);
				}
				if (val3 != null)
				{
					h.EquipItem(val3, true);
				}
				VanillaAccess.HiddenRightItem.Invoke(h) = (StillHolsterable(h, val) ? val : null);
				VanillaAccess.HiddenLeftItem.Invoke(h) = (StillHolsterable(h, val2) ? val2 : null);
				if (val != null || val2 != null)
				{
					LastRight = val;
					LastLeft = val2;
				}
				VanillaAccess.SetupVisEquipment(h);
				VanillaAccess.TriggerHolsterAnim(h);
			}
			finally
			{
				Busy = false;
			}
			return true;
		}

		private static bool UsesBothHands(ItemData item)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			SharedData val = item?.m_shared;
			if (val == null)
			{
				return false;
			}
			ItemType itemType = val.m_itemType;
			if ((int)itemType == 4 || (int)itemType == 14 || (int)itemType == 22)
			{
				return true;
			}
			return false;
		}

		private static void SetDualLeftMark(ItemData item, bool left)
		{
			if (item != null)
			{
				if (item.m_customData == null)
				{
					item.m_customData = new Dictionary<string, string>();
				}
				if (left)
				{
					item.m_customData["morgnar.dualwield.lefthand"] = "1";
				}
				else
				{
					item.m_customData.Remove("morgnar.dualwield.lefthand");
				}
			}
		}

		public static void EquipHands(Player p, ItemData pickR, ItemData pickL)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			if ((pickR == null && pickL == null) || ((Character)p).InAttack() || ((Character)p).InDodge())
			{
				return;
			}
			ItemData val = VanillaAccess.RightItem.Invoke((Humanoid)(object)p);
			ItemData val2 = VanillaAccess.LeftItem.Invoke((Humanoid)(object)p);
			if (pickR != null && pickR == pickL)
			{
				pickL = null;
			}
			if (IsShield(pickR))
			{
				if (pickL == null)
				{
					pickL = pickR;
				}
				pickR = null;
			}
			if (pickL != null && !DualWieldInstalled && (int)pickL.m_shared.m_itemType == 3)
			{
				if (pickR == null)
				{
					pickR = pickL;
				}
				pickL = null;
			}
			ItemData val3 = pickR ?? val;
			ItemData val4 = pickL ?? val2;
			if (UsesBothHands(val3))
			{
				val4 = ((pickL != null && pickR == null) ? pickL : null);
			}
			if (UsesBothHands(val4))
			{
				val3 = val4;
				val4 = null;
			}
			if (val4 != null && val4 == val3)
			{
				val4 = null;
			}
			if (pickL != null && pickR == null && UsesBothHands(val))
			{
				val3 = null;
			}
			if (val3 == val && val4 == val2)
			{
				return;
			}
			ItemData val5 = VanillaAccess.HiddenRightItem.Invoke((Humanoid)(object)p);
			ItemData val6 = VanillaAccess.HiddenLeftItem.Invoke((Humanoid)(object)p);
			Busy = true;
			try
			{
				if (val != null)
				{
					((Humanoid)p).UnequipItem(val, false);
				}
				if (val2 != null)
				{
					((Humanoid)p).UnequipItem(val2, false);
				}
				if (val3 != null)
				{
					SetDualLeftMark(val3, left: false);
					((Humanoid)p).EquipItem(val3, true);
				}
				if (val4 != null)
				{
					SetDualLeftMark(val4, left: true);
					((Humanoid)p).EquipItem(val4, val3 == null);
				}
				ItemData val7 = ((val != null && !val.m_equipped) ? val : null);
				ItemData val8 = ((val2 != null && !val2.m_equipped) ? val2 : null);
				VanillaAccess.HiddenRightItem.Invoke((Humanoid)(object)p) = (StillHolsterable((Humanoid)(object)p, val7) ? val7 : (StillHolsterable((Humanoid)(object)p, val5) ? val5 : null));
				VanillaAccess.HiddenLeftItem.Invoke((Humanoid)(object)p) = (StillHolsterable((Humanoid)(object)p, val8) ? val8 : (StillHolsterable((Humanoid)(object)p, val6) ? val6 : null));
				if (val7 != null || val8 != null)
				{
					LastRight = val7;
					LastLeft = val8;
				}
				VanillaAccess.SetupVisEquipment((Humanoid)(object)p);
			}
			finally
			{
				Busy = false;
			}
			ExtraHolster.MarkDirty();
		}

		public static ItemData FindBestShield(Humanoid h)
		{
			Inventory inventory = h.GetInventory();
			if (inventory == null)
			{
				return null;
			}
			ItemData result = null;
			float num = float.MinValue;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (IsShield(allItem) && (!allItem.m_shared.m_useDurability || !(allItem.m_durability <= 0f)))
				{
					float baseBlockPower = allItem.GetBaseBlockPower(allItem.m_quality);
					if (baseBlockPower > num)
					{
						num = baseBlockPower;
						result = allItem;
					}
				}
			}
			return result;
		}

		public static void TryAutoEquipShield(Humanoid h, ItemData weapon)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			if (!HolsterConfig.AutoEquipShield.Value || !IsOneHandWeapon(weapon) || VanillaAccess.LeftItem.Invoke(h) != null || (HolsterConfig.NoShieldWithAxe.Value && (int)weapon.m_shared.m_skillType == 7))
			{
				return;
			}
			ItemData val = FindBestShield(h);
			if (val == null || val.m_equipped)
			{
				return;
			}
			ItemData val2 = VanillaAccess.HiddenRightItem.Invoke(h);
			ItemData val3 = VanillaAccess.HiddenLeftItem.Invoke(h);
			Busy = true;
			try
			{
				if (val3 == val)
				{
					val3 = null;
				}
				h.EquipItem(val, false);
				VanillaAccess.HiddenRightItem.Invoke(h) = (StillHolsterable(h, val2) ? val2 : null);
				VanillaAccess.HiddenLeftItem.Invoke(h) = (StillHolsterable(h, val3) ? val3 : null);
				VanillaAccess.SetupVisEquipment(h);
			}
			finally
			{
				Busy = false;
			}
		}

		public static void TryAutoUnequipShield(Humanoid h)
		{
			if (!HolsterConfig.AutoUnequipShield.Value)
			{
				return;
			}
			ItemData val = VanillaAccess.LeftItem.Invoke(h);
			if (!IsShield(val) || IsOneHandWeapon(VanillaAccess.RightItem.Invoke(h)))
			{
				return;
			}
			Busy = true;
			try
			{
				h.UnequipItem(val, false);
				if (StillHolsterable(h, val))
				{
					VanillaAccess.HiddenLeftItem.Invoke(h) = val;
					VanillaAccess.SetupVisEquipment(h);
				}
			}
			finally
			{
				Busy = false;
			}
		}

		private static bool TextBlocked()
		{
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return true;
			}
			if (Console.IsVisible())
			{
				return true;
			}
			if (TextInput.IsVisible())
			{
				return true;
			}
			if (Menu.IsVisible())
			{
				return true;
			}
			return false;
		}

		public static void HandleHotkeys()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && HolsterConfig.Enabled.Value)
			{
				KeyCode value = HolsterConfig.MarkKey.Value;
				if ((int)value != 0 && InventoryGui.IsVisible() && !TextBlocked() && UnityInput.Current.GetKeyDown(value))
				{
					ToggleMark(localPlayer);
				}
			}
		}

		public static bool IsMarked(ItemData item)
		{
			if (item?.m_customData != null)
			{
				return item.m_customData.ContainsKey("ValheimHolster.Marked");
			}
			return false;
		}

		public static void SetMarked(ItemData item, bool marked)
		{
			if (item != null)
			{
				if (item.m_customData == null)
				{
					item.m_customData = new Dictionary<string, string>();
				}
				if (marked)
				{
					item.m_customData["ValheimHolster.Marked"] = "1";
				}
				else
				{
					item.m_customData.Remove("ValheimHolster.Marked");
				}
			}
		}

		public static int ItemHash(ItemData item)
		{
			if (!((Object)(object)item?.m_dropPrefab != (Object)null))
			{
				return 0;
			}
			return StringExtensionMethods.GetStableHashCode(((Object)item.m_dropPrefab).name);
		}

		public static IEnumerable<ItemData> SortedInventory(Inventory inv)
		{
			return from i in inv.GetAllItems()
				where i != null
				orderby i.m_gridPos.y, i.m_gridPos.x
				select i;
		}

		public static IEnumerable<ItemData> PlacementOrder(Inventory inv)
		{
			return from i in SortedInventory(inv)
				orderby HolsterJoints.IsDualWeapon(i.m_shared) ? 1 : 0
				select i;
		}

		public static List<ItemData> WheelItems(Player p)
		{
			List<ItemData> list = new List<ItemData>();
			Inventory inventory = ((Humanoid)p).GetInventory();
			if (inventory == null)
			{
				return list;
			}
			ItemData val = VanillaAccess.HiddenRightItem.Invoke((Humanoid)(object)p);
			ItemData val2 = VanillaAccess.HiddenLeftItem.Invoke((Humanoid)(object)p);
			foreach (ItemData item in SortedInventory(inventory))
			{
				if (item.m_equipped || !CanHolster(item) || (IsShield(item) && !DualWieldInstalled))
				{
					continue;
				}
				bool flag = item == val || item == val2;
				if (!HolsterConfig.WheelOnlyMarked.Value || IsMarked(item) || flag)
				{
					list.Add(item);
					if (list.Count >= 12)
					{
						break;
					}
				}
			}
			return list;
		}

		public static void TapHide(Player p)
		{
			ModCall = true;
			bool hideKeyThisFrame = HideKeyThisFrame;
			HideKeyThisFrame = true;
			try
			{
				if (VanillaAccess.RightItem.Invoke((Humanoid)(object)p) != null || VanillaAccess.LeftItem.Invoke((Humanoid)(object)p) != null)
				{
					if (!((Character)p).InAttack() && !((Character)p).InDodge())
					{
						((Humanoid)p).HideHandItems(false, true);
					}
				}
				else
				{
					if ((((Character)p).IsSwimming() && !((Character)p).IsOnGround()) || ((Character)p).InDodge())
					{
						return;
					}
					if (VanillaAccess.HiddenRightItem.Invoke((Humanoid)(object)p) == null && VanillaAccess.HiddenLeftItem.Invoke((Humanoid)(object)p) == null)
					{
						ItemData val = (UsableLast((Humanoid)(object)p, LastLeft) ? LastLeft : null);
						ItemData val2 = (UsableLast((Humanoid)(object)p, LastRight) ? LastRight : null);
						bool num = val != null && val2 != null;
						bool busy = Busy;
						if (num)
						{
							Busy = true;
						}
						try
						{
							if (val != null)
							{
								((Humanoid)p).EquipItem(val, true);
							}
							if (val2 != null)
							{
								((Humanoid)p).EquipItem(val2, true);
							}
							return;
						}
						finally
						{
							Busy = busy;
						}
					}
					VanillaAccess.ShowHandItems((Humanoid)(object)p);
				}
			}
			finally
			{
				ModCall = false;
				HideKeyThisFrame = hideKeyThisFrame;
			}
		}

		public static bool IsAxeOrMace(SharedData s)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			if (s != null)
			{
				if ((int)s.m_skillType != 7)
				{
					return (int)s.m_skillType == 3;
				}
				return true;
			}
			return false;
		}

		public static void ApplyHipOffset(Transform t, bool left, Transform character, SharedData s)
		{
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: 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_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)character == (Object)null))
			{
				bool num = IsKnife(s);
				bool flag = !num && HolsterConfig.AxeHeadUp.Value && IsAxeOrMace(s);
				float num2 = (num ? HolsterConfig.KnifeTilt.Value : (flag ? HolsterConfig.AxeTilt.Value : HolsterConfig.HipTiltBack.Value));
				float num3 = (num ? HolsterConfig.KnifeRoll.Value : (flag ? 0f : HolsterConfig.HipRollOut.Value));
				float num4 = (num ? HolsterConfig.KnifeUp.Value : (flag ? (HolsterConfig.HipUp.Value + HolsterConfig.AxeUp.Value) : HolsterConfig.HipUp.Value));
				float num5 = (num ? HolsterConfig.KnifeForward.Value : HolsterConfig.HipForward.Value);
				float num6 = (num ? HolsterConfig.KnifeInward.Value : HolsterConfig.HipInward.Value);
				float num7 = (left ? 1f : (-1f));
				Vector3 right = character.right;
				Vector3 up = character.up;
				Vector3 forward = character.forward;
				Quaternion val = Quaternion.AngleAxis(num3 * num7, forward) * Quaternion.AngleAxis(num2, right);
				Vector3 val2 = val * (flag ? up : (-up));
				Vector3 val3 = val * forward;
				float num8 = 0f;
				if (TryGetBladeAxes(t, out var blade, out var edge, out var length))
				{
					Quaternion val4 = Quaternion.LookRotation(val2, val3);
					Quaternion val5 = Quaternion.LookRotation(blade, edge);
					t.rotation = val4 * Quaternion.Inverse(val5);
					num8 = length * Mathf.Abs(t.lossyScale.x);
				}
				else
				{
					t.rotation = val * t.rotation;
				}
				Vector3 value = HolsterConfig.HipPositionOffset.Value;
				Vector3 value2 = HolsterConfig.HipRotationOffset.Value;
				if (left)
				{
					value.x = 0f - value.x;
					value2.y = 0f - value2.y;
					value2.z = 0f - value2.z;
				}
				t.rotation *= Quaternion.Euler(value2);
				if (flag && num8 > 0f)
				{
					t.position -= val2 * (num8 * 0.75f);
				}
				float num9 = Mathf.Abs(character.lossyScale.x);
				t.position += (up * num4 + forward * num5 - num7 * right * num6 + right * value.x + up * value.y + forward * value.z) * num9;
			}
		}

		private static bool TryGetBladeAxes(Transform root, out Vector3 blade, out Vector3 edge, out float length)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			blade = Vector3.zero;
			edge = Vector3.zero;
			length = 0f;
			bool flag = false;
			Vector3 val = Vector3.positiveInfinity;
			Vector3 val2 = Vector3.negativeInfinity;
			Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(false);
			foreach (Renderer val3 in componentsInChildren)
			{
				if (!val3.enabled)
				{
					continue;
				}
				Mesh val4 = null;
				if (val3 is MeshRenderer)
				{
					MeshFilter component = ((Component)val3).GetComponent<MeshFilter>();
					if ((Object)(object)component != (Object)null)
					{
						val4 = component.sharedMesh;
					}
				}
				else
				{
					SkinnedMeshRenderer val5 = (SkinnedMeshRenderer)(object)((val3 is SkinnedMeshRenderer) ? val3 : null);
					if (val5 != null)
					{
						val4 = val5.sharedMesh;
					}
				}
				if (!((Object)(object)val4 == (Object)null))
				{
					Bounds bounds = val4.bounds;
					Matrix4x4 val6 = root.worldToLocalMatrix * ((Component)val3).transform.localToWorldMatrix;
					for (int j = 0; j < 8; j++)
					{
						Vector3 val7 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1))));
						Vector3 val8 = ((Matrix4x4)(ref val6)).MultiplyPoint3x4(val7);
						val = Vector3.Min(val, val8);
						val2 = Vector3.Max(val2, val8);
						flag = true;
					}
				}
			}
			if (!flag)
			{
				return false;
			}
			Vector3 val9 = val2 - val;
			int num = 0;
			if (val9.y > ((Vector3)(ref val9))[num])
			{
				num = 1;
			}
			if (val9.z > ((Vector3)(ref val9))[num])
			{
				num = 2;
			}
			int num2 = ((num == 0) ? 1 : 0);
			for (int k = 0; k < 3; k++)
			{
				if (k != num && ((Vector3)(ref val9))[k] > ((Vector3)(ref val9))[num2])
				{
					num2 = k;
				}
			}
			if (((Vector3)(ref val9))[num] < 0.01f)
			{
				return false;
			}
			float num3 = ((Mathf.Abs(((Vector3)(ref val2))[num]) >= Mathf.Abs(((Vector3)(ref val))[num])) ? 1f : (-1f));
			blade = Vector3.zero;
			((Vector3)(ref blade))[num] = num3;
			edge = Vector3.zero;
			((Vector3)(ref edge))[num2] = 1f;
			length = Mathf.Max(Mathf.Abs(((Vector3)(ref val2))[num]), Mathf.Abs(((Vector3)(ref val))[num]));
			return true;
		}

		public static bool IsKnife(SharedData s)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			if (s != null)
			{
				return (int)s.m_skillType == 2;
			}
			return false;
		}

		public static void EmptyHands(Player p)
		{
			if (((Character)p).InAttack() || ((Character)p).InDodge())
			{
				return;
			}
			ItemData val = VanillaAccess.RightItem.Invoke((Humanoid)(object)p);
			ItemData val2 = VanillaAccess.LeftItem.Invoke((Humanoid)(object)p);
			if (val == null && val2 == null)
			{
				return;
			}
			ItemData val3 = VanillaAccess.HiddenRightItem.Invoke((Humanoid)(object)p);
			ItemData val4 = VanillaAccess.HiddenLeftItem.Invoke((Humanoid)(object)p);
			LastRight = val;
			LastLeft = val2;
			Busy = true;
			try
			{
				if (val != null)
				{
					((Humanoid)p).UnequipItem(val, false);
				}
				if (val2 != null)
				{
					((Humanoid)p).UnequipItem(val2, false);
				}
				VanillaAccess.HiddenRightItem.Invoke((Humanoid)(object)p) = (StillHolsterable((Humanoid)(object)p, val) ? val : (StillHolsterable((Humanoid)(object)p, val3) ? val3 : null));
				VanillaAccess.HiddenLeftItem.Invoke((Humanoid)(object)p) = (StillHolsterable((Humanoid)(object)p, val2) ? val2 : (StillHolsterable((Humanoid)(object)p, val4) ? val4 : null));
				VanillaAccess.SetupVisEquipment((Humanoid)(object)p);
				VanillaAccess.TriggerHolsterAnim((Humanoid)(object)p);
			}
			finally
			{
				Busy = false;
			}
			ExtraHolster.MarkDirty();
		}

		private static void ToggleMark(Player player)
		{
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			ItemData hoveredPlayerItem = VanillaAccess.GetHoveredPlayerItem();
			if (hoveredPlayerItem == null)
			{
				if (HolsterConfig.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)("Marcar: nenhum item sob o mouse (" + HoverTracker.Describe() + ")"));
				}
				return;
			}
			string text = ((Localization.instance != null) ? Localization.instance.Localize(hoveredPlayerItem.m_shared.m_name) : hoveredPlayerItem.m_shared.m_name);
			if (!IsHandItem(hoveredPlayerItem))
			{
				((Character)player).Message((MessageType)1, Loc.T("This item can't stay on your body.", "Esse item não pode ficar no corpo."), 0, (Sprite)null, false);
				return;
			}
			if (IsTool(hoveredPlayerItem) && !HolsterConfig.HolsterTools.Value)
			{
				((Character)player).Message((MessageType)1, Loc.T("Tools never stay on your body.", "Ferramentas nunca são guardadas no corpo."), 0, (Sprite)null, false);
				return;
			}
			bool flag = !IsMarked(hoveredPlayerItem);
			SetMarked(hoveredPlayerItem, flag);
			if (!flag && HolsterConfig.OnlyMarked.Value)
			{
				bool flag2 = false;
				if (VanillaAccess.HiddenRightItem.Invoke((Humanoid)(object)player) == hoveredPlayerItem)
				{
					VanillaAccess.HiddenRightItem.Invoke((Humanoid)(object)player) = null;
					flag2 = true;
				}
				if (VanillaAccess.HiddenLeftItem.Invoke((Humanoid)(object)player) == hoveredPlayerItem)
				{
					VanillaAccess.HiddenLeftItem.Invoke((Humanoid)(object)player) = null;
					flag2 = true;
				}
				if (flag2)
				{
					VanillaAccess.SetupVisEquipment((Humanoid)(object)player);
				}
			}
			if (HolsterConfig.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)string.Format("Marcar: {0} tipo={1} attach={2} skill={3} -> {4}", hoveredPlayerItem.m_shared.m_name, hoveredPlayerItem.m_shared.m_itemType, hoveredPlayerItem.m_shared.m_attachOverride, hoveredPlayerItem.m_shared.m_skillType, flag ? "marcado" : "desmarcado"));
			}
			((Character)player).Message((MessageType)1, flag ? Loc.T(text + ": stays on your body", text + ": fica no corpo") : Loc.T(text + ": won't stay on your body", text + ": não fica no corpo"), 0, (Sprite)null, false);
			ExtraHolster.MarkDirty();
		}
	}
	internal static class HolsterWheel
	{
		private class Slot
		{
			public RectTransform Root;

			public CanvasGroup Group;

			public Image Glow;

			public Image Base;

			public Image Rim;

			public Image Icon;

			public TMP_Text Badge;

			public float Pop;

			public bool Holstered;
		}

		private const float RingRadius = 175f;

		private const float SlotSize = 84f;

		private const float IconSize = 58f;

		private const float MouseStep = 55f;

		private const float SpinSmooth = 0.075f;

		private const float FadeInTime = 0.14f;

		private const float FadeOutTime = 0.1f;

		private const float SlotInTime = 0.22f;

		private const float SlotStagger = 0.03f;

		private const float LabelPopTime = 0.16f;

		private const float SelectSpring = 18f;

		private static readonly Color Gold = new Color(1f, 0.78f, 0.38f, 1f);

		private static readonly Color BgCenter = new Color(0f, 0f, 0f, 0.92f);

		private static readonly Color PlateColor = new Color(0.03f, 0.025f, 0.02f, 0.88f);

		private static readonly Color TrackColor = new Color(1f, 0.82f, 0.5f, 0.28f);

		private static readonly Color SlotBase = new Color(0.03f, 0.025f, 0.02f, 0.95f);

		private static readonly Color SlotBaseSelected = new Color(0.2f, 0.12f, 0.04f, 0.97f);

		private static readonly Color RimIdle = new Color(1f, 0.85f, 0.6f, 0.35f);

		private static readonly Color RimHolstered = new Color(0.55f, 0.8f, 1f, 0.6f);

		private static readonly Color LabelColor = new Color(1f, 0.92f, 0.75f, 1f);

		private static readonly Color SubLabelColor = new Color(0.8f, 0.74f, 0.62f, 0.85f);

		private static readonly Color PickColor = new Color(0.45f, 1f, 0.55f, 1f);

		private static readonly Color HintColor = new Color(0.8f, 0.74f, 0.62f, 0.7f);

		private static float _swallowUntil;

		private static float _holdStart;

		private static float _pendingTapAt = -1f;

		private static bool _secondPress;

		private static float _openedAt;

		private static float _closingAt = -1f;

		private static float _labelChangedAt;

		private static List<ItemData> _items = new List<ItemData>();

		private static ItemData _pickR;

		private static ItemData _pickL;

		private static int _targetIndex;

		private static float _currentIndex;

		private static float _spinVelocity;

		private static float _mouseAccum;

		private static int _shownSelected = -1;

		private static GameObject _root;

		private static CanvasGroup _group;

		private static RectTransform _content;

		private static RectTransform _ring;

		private static RectTransform _pointer;

		private static TMP_Text _label;

		private static TMP_Text _subLabel;

		private static TMP_Text _picksLabel;

		private static TMP_Text _hint;

		private static readonly List<Slot> _slots = new List<Slot>();

		private static bool _gamepad;

		private static bool _joyWheelUsed;

		private static float _stickRepeatAt;

		private const float StickRepeat = 0.2f;

		private static TMP_FontAsset _font;

		public static bool Holding { get; private set; }

		public static bool IsOpen { get; private set; }

		public static bool BlocksInput
		{
			get
			{
				if (!IsOpen)
				{
					return Time.unscaledTime < _swallowUntil;
				}
				return true;
			}
		}

		private static int Selected
		{
			get
			{
				if (_items.Count != 0)
				{
					return Mod(_targetIndex, _items.Count);
				}
				return -1;
			}
		}

		private static float Dt => Time.unscaledDeltaTime;

		private static float Now => Time.unscaledTime;

		private static int Mod(int a, int n)
		{
			return (a % n + n) % n;
		}

		public static void OnHideDown()
		{
			Holding = true;
			_gamepad = false;
			_holdStart = Now;
			_secondPress = _pendingTapAt >= 0f && Now - _pendingTapAt <= HolsterConfig.DoubleTapWindow.Value;
		}

		public static void OnJoyHideDown()
		{
			Holding = true;
			_gamepad = true;
			_joyWheelUsed = false;
			_holdStart = Now;
			_secondPress = false;
		}

		public static bool ConsumeJoyRelease()
		{
			bool joyWheelUsed = _joyWheelUsed;
			_joyWheelUsed = false;
			return joyWheelUsed;
		}

		public static void Tick()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || InventoryGui.IsVisible() || Menu.IsVisible())
			{
				Holding = false;
				_pendingTapAt = -1f;
				_secondPress = false;
				Close(instant: true);
				return;
			}
			if (IsOpen || _closingAt >= 0f)
			{
				Animate();
			}
			if (!Holding && _pendingTapAt >= 0f && Now - _pendingTapAt > HolsterConfig.DoubleTapWindow.Value)
			{
				_pendingTapAt = -1f;
				HolsterLogic.TapHide(localPlayer);
			}
			if (!Holding)
			{
				return;
			}
			if (_gamepad ? ZInput.GetButton("JoyHide") : ZInput.GetButton("Hide"))
			{
				if (!IsOpen && !_secondPress && Now - _holdStart >= HolsterConfig.WheelHoldTime.Value)
				{
					_items = HolsterLogic.WheelItems(localPlayer);
					if (_items.Count > 0)
					{
						Open(localPlayer);
						if (_gamepad)
						{
							_joyWheelUsed = true;
						}
					}
				}
				if (IsOpen && _gamepad)
				{
					if (ZInput.GetButtonDown("JoyButtonB"))
					{
						Holding = false;
						Close(instant: false);
					}
					else
					{
						ReadStickInput();
					}
				}
				else
				{
					if (!IsOpen)
					{
						return;
					}
					bool dualWieldInstalled = HolsterLogic.DualWieldInstalled;
					if (UnityInput.Current.GetMouseButtonDown(2) || (!dualWieldInstalled && UnityInput.Current.GetMouseButtonDown(1)))
					{
						Holding = false;
						Close(instant: false);
						return;
					}
					if (dualWieldInstalled)
					{
						ReadPickInput();
					}
					ReadSpinInput();
				}
				return;
			}
			Holding = false;
			if (IsOpen)
			{
				int selected = Selected;
				ItemData val = ((selected >= 0) ? _items[selected] : null);
				ItemData pickR = _pickR;
				ItemData pickL = _pickL;
				Close(instant: false);
				if (pickR != null || pickL != null)
				{
					HolsterLogic.EquipHands(localPlayer, pickR, pickL);
				}
				else if (val != null && !val.m_equipped && !((Character)localPlayer).InAttack() && !((Character)localPlayer).InDodge())
				{
					((Humanoid)localPlayer).EquipItem(val, true);
				}
			}
			else if (!_gamepad)
			{
				if (_secondPress)
				{
					_secondPress = false;
					_pendingTapAt = -1f;
					HolsterLogic.EmptyHands(localPlayer);
				}
				else if (HolsterConfig.DoubleTapEmpty.Value && (VanillaAccess.RightItem.Invoke((Humanoid)(object)localPlayer) != null || VanillaAccess.LeftItem.Invoke((Humanoid)(object)localPlayer) != null))
				{
					_pendingTapAt = Now;
				}
				else
				{
					HolsterLogic.TapHide(localPlayer);
				}
			}
		}

		private static void ReadPickInput()
		{
			int selected = Selected;
			if (selected < 0)
			{
				return;
			}
			ItemData val = _items[selected];
			if (UnityInput.Current.GetMouseButtonDown(0))
			{
				if (_pickL == val)
				{
					_pickL = null;
				}
				else
				{
					_pickL = val;
					if (_pickR == val)
					{
						_pickR = null;
					}
				}
				UpdatePicksLabel();
			}
			if (!UnityInput.Current.GetMouseButtonDown(1))
			{
				return;
			}
			if (_pickR == val)
			{
				_pickR = null;
			}
			else
			{
				_pickR = val;
				if (_pickL == val)
				{
					_pickL = null;
				}
			}
			UpdatePicksLabel();
		}

		private static string ItemName(ItemData item)
		{
			if (Localization.instance == null)
			{
				return item.m_shared.m_name;
			}
			return Localization.instance.Localize(item.m_shared.m_name);
		}

		private static void UpdatePicksLabel()
		{
			if (!((Object)(object)_picksLabel == (Object)null))
			{
				string text = ((_pickL != null) ? ItemName(_pickL) : "—");
				string text2 = ((_pickR != null) ? ItemName(_pickR) : "—");
				_picksLabel.text = ((_pickL == null && _pickR == null) ? "" : ("E: " + text + "   ·   D: " + text2));
			}
		}

		private static void ReadStickInput()
		{
			if (_items.Count > 1)
			{
				float num = ZInput.GetJoyRightStickX();
				if (Mathf.Abs(num) < 0.15f)
				{
					num = (ZInput.GetButton("JoyDPadRight") ? 1f : (ZInput.GetButton("JoyDPadLeft") ? (-1f) : 0f));
				}
				if (Mathf.Abs(num) < 0.5f)
				{
					_stickRepeatAt = 0f;
				}
				else if (!(Now < _stickRepeatAt))
				{
					_targetIndex += ((num > 0f) ? 1 : (-1));
					_stickRepeatAt = Now + ((_stickRepeatAt == 0f) ? 0.32000002f : 0.2f);
				}
			}
		}

		private static void ReadSpinInput()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if (_items.Count > 1)
			{
				_mouseAccum += ZInput.GetMouseDelta().x;
				while (_mouseAccum >= 55f)
				{
					_targetIndex++;
					_mouseAccum -= 55f;
				}
				while (_mouseAccum <= -55f)
				{
					_targetIndex--;
					_mouseAccum += 55f;
				}
				float y = UnityInput.Current.mouseScrollDelta.y;
				if (y > 0.01f)
				{
					_targetIndex--;
				}
				else if (y < -0.01f)
				{
					_targetIndex++;
				}
			}
		}

		private static void Open(Player p)
		{
			EnsureUI();
			_group.alpha = 0f;
			_root.SetActive(true);
			IsOpen = true;
			_closingAt = -1f;
			_openedAt = Now;
			_mouseAccum = 0f;
			_spinVelocity = 0f;
			_shownSelected = -1;
			_pickR = null;
			_pickL = null;
			ItemData val = VanillaAccess.HiddenRightItem.Invoke((Humanoid)(object)p);
			ItemData val2 = VanillaAccess.HiddenLeftItem.Invoke((Humanoid)(object)p);
			_targetIndex = 0;
			for (int i = 0; i < _items.Count; i++)
			{
				if (_items[i] == val || _items[i] == val2)
				{
					_targetIndex = i;
					break;
				}
			}
			_currentIndex = (float)_targetIndex - 1.2f;
			foreach (Slot slot in _slots)
			{
				Object.Destroy((Object)(object)((Component)slot.Root).gameObject);
			}
			_slots.Clear();
			try
			{
				for (int j = 0; j < _items.Count; j++)
				{
					_slots.Add(CreateSlot(j, _items[j], _items[j] == val || _items[j] == val2));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Roda: falha ao montar os slots: " + ex.Message));
				IsOpen = false;
				_root.SetActive(false);
				return;
			}
			SetLabels(null);
			UpdatePicksLabel();
			_hint.text = (_gamepad ? Loc.T("Right stick: spin   ·   release to equip   ·   B: cancel", "Analógico direito: girar   ·   solte pra equipar   ·   B: cancelar") : (HolsterLogic.DualWieldInstalled ? Loc.T("Left click: left hand   ·   right click: right hand   ·   middle: cancel", "Clique esq.: mão esquerda   ·   dir.: mão direita   ·   meio: cancelar") : Loc.T("Release R to equip   ·   right click: cancel", "Solte o R pra equipar   ·   botão direito: cancelar")));
			Animate();
		}

		private static void Close(bool instant)
		{
			if (!IsOpen && _closingAt < 0f)
			{
				return;
			}
			IsOpen = false;
			if (_gamepad)
			{
				_swallowUntil = Now + 0.2f;
			}
			if (instant || (Object)(object)_root == (Object)null)
			{
				_closingAt = -1f;
				if ((Object)(object)_root != (Object)null)
				{
					_root.SetActive(false);
				}
			}
			else if (_closingAt < 0f)
			{
				_closingAt = Now;
			}
		}

		private static void Animate()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_044b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0452: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_root == (Object)null)
			{
				return;
			}
			if (!IsOpen)
			{
				float num = Mathf.Clamp01((Now - _closingAt) / 0.1f);
				_group.alpha = 1f - num;
				((Transform)_content).localScale = Vector3.one * Mathf.Lerp(1f, 0.9f, UiUtil.EaseOutCubic(num));
				if (num >= 1f)
				{
					_closingAt = -1f;
					_root.SetActive(false);
				}
				return;
			}
			int count = _items.Count;
			if (count == 0 || _slots.Count