Decompiled source of Quick Pin v1.0.3

plugins/FrostJack.QuickPin.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Xml.Linq;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ValheimSleepMod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ValheimSleepMod")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("816f803f-c779-42bb-99a6-2eb5f1ba60b5")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("FrostJack.QuickPin", "QuickPin", "1.1.0")]
public class QuickPinPlugin : BaseUnityPlugin
{
	private class PinItem
	{
		public string Name { get; set; }

		public PinType PinType { get; set; }
	}

	[HarmonyPatch(typeof(Hud), "UpdateCrosshair")]
	public static class UpdateCrosshairPatch
	{
		private class Sparkle
		{
			public RectTransform rt;

			public Image img;

			public Vector2 vel;

			public float t;

			public float life;

			public float startSize;

			public Color startColor;
		}

		private static bool _initialized;

		private static bool _isHolding;

		private static float _holdStart;

		private static GameObject s_ringRoot;

		private static Image s_ringBg;

		private static Image s_ringFg;

		private static readonly List<Sparkle> s_sparkles = new List<Sparkle>();

		private static float s_sparkleTimer;

		private const float RingSize = 45f;

		public static void CleanupStatic()
		{
			_initialized = false;
			_isHolding = false;
			_holdStart = 0f;
			if ((Object)(object)s_ringRoot != (Object)null)
			{
				Object.Destroy((Object)(object)s_ringRoot);
				s_ringRoot = null;
				s_ringBg = null;
				s_ringFg = null;
			}
			for (int i = 0; i < s_sparkles.Count; i++)
			{
				if (Object.op_Implicit((Object)(object)s_sparkles[i]?.rt))
				{
					Object.Destroy((Object)(object)((Component)s_sparkles[i].rt).gameObject);
				}
			}
			s_sparkles.Clear();
			s_sparkleTimer = 0f;
		}

		private static void CancelHold()
		{
			if (_isHolding)
			{
				_isHolding = false;
			}
			_holdStart = 0f;
			HideRing();
		}

		private static void EnsureRing(Hud hud)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: 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_01d1: Expected O, but got Unknown
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)s_ringRoot != (Object)null))
			{
				Transform val = (((Object)(object)hud.m_crosshair != (Object)null) ? ((Component)hud.m_crosshair).transform.parent : ((Component)hud).transform);
				s_ringRoot = new GameObject("QuickPinRing");
				s_ringRoot.transform.SetParent(val, false);
				RectTransform val2 = s_ringRoot.AddComponent<RectTransform>();
				val2.anchorMin = new Vector2(0.5f, 0.5f);
				val2.anchorMax = new Vector2(0.5f, 0.5f);
				val2.pivot = new Vector2(0.5f, 0.5f);
				val2.anchoredPosition = Vector2.zero;
				val2.sizeDelta = new Vector2(45f, 45f);
				GameObject val3 = new GameObject("BG");
				val3.transform.SetParent(s_ringRoot.transform, false);
				RectTransform val4 = val3.AddComponent<RectTransform>();
				Vector2 val5 = default(Vector2);
				((Vector2)(ref val5))..ctor(0.5f, 0.5f);
				val4.pivot = val5;
				Vector2 anchorMin = (val4.anchorMax = val5);
				val4.anchorMin = anchorMin;
				val4.sizeDelta = new Vector2(45f, 45f);
				s_ringBg = val3.AddComponent<Image>();
				((Graphic)s_ringBg).raycastTarget = false;
				((Graphic)s_ringBg).color = new Color(1f, 1f, 1f, 0.18f);
				s_ringBg.type = (Type)0;
				s_ringBg.sprite = (((Object)(object)hud.m_crosshairBow != (Object)null) ? hud.m_crosshairBow.sprite : (((Object)(object)hud.m_crosshair != (Object)null) ? hud.m_crosshair.sprite : null));
				GameObject val7 = new GameObject("FG");
				val7.transform.SetParent(s_ringRoot.transform, false);
				RectTransform val8 = val7.AddComponent<RectTransform>();
				((Vector2)(ref val5))..ctor(0.5f, 0.5f);
				val8.pivot = val5;
				anchorMin = (val8.anchorMax = val5);
				val8.anchorMin = anchorMin;
				val8.sizeDelta = new Vector2(45f, 45f);
				s_ringFg = val7.AddComponent<Image>();
				((Graphic)s_ringFg).raycastTarget = false;
				((Graphic)s_ringFg).color = Color.white;
				s_ringFg.type = (Type)3;
				s_ringFg.fillMethod = (FillMethod)4;
				s_ringFg.fillOrigin = 2;
				s_ringFg.fillClockwise = true;
				s_ringFg.fillAmount = 0f;
				s_ringFg.sprite = s_ringBg.sprite;
				s_ringRoot.SetActive(false);
			}
		}

		private static bool IsDungeonEntrance(GameObject obj, out Teleport teleport)
		{
			teleport = null;
			if (!EnableDungeonEntrancesConfig.Value)
			{
				return false;
			}
			if ((Object)(object)obj == (Object)null)
			{
				return false;
			}
			teleport = obj.GetComponentInParent<Teleport>();
			if ((Object)(object)teleport == (Object)null || (Object)(object)teleport.m_targetPoint == (Object)null)
			{
				return false;
			}
			Transform val = ((Component)teleport).transform;
			while ((Object)(object)val != (Object)null)
			{
				string text = ((Object)val).name;
				if (text.EndsWith("(Clone)"))
				{
					text = text.Substring(0, text.Length - 7);
				}
				if (AllowedPortalIds.ContainsKey(text))
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static bool IsAllowedPrefab(GameObject obj, out string id, out string pinName, out PinType pinType)
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected I4, but got Unknown
			id = null;
			pinName = null;
			pinType = (PinType)3;
			if ((Object)(object)obj == (Object)null)
			{
				return false;
			}
			ZNetView componentInParent = obj.GetComponentInParent<ZNetView>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return false;
			}
			ZDO zDO = componentInParent.GetZDO();
			if (zDO == null)
			{
				return false;
			}
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return false;
			}
			int prefab = zDO.GetPrefab();
			GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
			if ((Object)(object)prefab2 == (Object)null)
			{
				return false;
			}
			id = ((Object)prefab2).name;
			if (!AllowedPrefabIds.TryGetValue(id, out var value))
			{
				return false;
			}
			pinName = value.Name;
			pinType = (PinType)(int)value.PinType;
			return true;
		}

		private static bool HasPinAtPositionWithName(Vector3 pos, string name)
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Minimap.instance == (Object)null)
			{
				return false;
			}
			Type type = ((object)Minimap.instance).GetType();
			FieldInfo fieldInfo = type.GetField("m_pins", BindingFlags.Instance | BindingFlags.NonPublic) ?? type.GetField("m_pinList", BindingFlags.Instance | BindingFlags.NonPublic) ?? type.GetField("m_pinsDict", BindingFlags.Instance | BindingFlags.NonPublic);
			if (fieldInfo == null)
			{
				return false;
			}
			if (!(fieldInfo.GetValue(Minimap.instance) is IEnumerable enumerable))
			{
				return false;
			}
			foreach (object item in enumerable)
			{
				if (item == null)
				{
					continue;
				}
				Type type2 = item.GetType();
				FieldInfo field = type2.GetField("m_pos", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				FieldInfo field2 = type2.GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (!(field == null) && !(field2 == null))
				{
					Vector3 val = (Vector3)field.GetValue(item);
					if (field2.GetValue(item) is string text && text.Equals(name, StringComparison.OrdinalIgnoreCase) && Vector3.Distance(pos, val) < 0.5f)
					{
						return true;
					}
				}
			}
			return false;
		}

		[HarmonyPostfix]
		public static void Postfix(Hud __instance, Player player, float bowDrawPercentage)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!_initialized)
				{
					_initialized = true;
				}
				if ((Object)(object)player == (Object)null)
				{
					return;
				}
				EnsureRing(__instance);
				TMP_Text hoverName = (TMP_Text)(object)__instance.m_hoverName;
				if ((Object)(object)hoverName == (Object)null)
				{
					CancelHold();
					return;
				}
				GameObject hoverObject = ((Humanoid)player).GetHoverObject();
				if ((Object)(object)hoverObject == (Object)null)
				{
					CancelHold();
					return;
				}
				string text = null;
				PinType val = (PinType)3;
				if (IsDungeonEntrance(hoverObject, out var teleport))
				{
					text = GetDungeonEntranceName(teleport);
					val = GetDungeonEntrancePinType(teleport);
				}
				else
				{
					if (!IsAllowedPrefab(hoverObject, out var _, out var pinName, out var pinType))
					{
						CancelHold();
						return;
					}
					text = pinName;
					val = pinType;
				}
				if (ShowHoldHintConfig.Value)
				{
					string text2 = BuildPinHint();
					if (!hoverName.text.Contains("Tag Location"))
					{
						hoverName.text = hoverName.text.TrimEnd(Array.Empty<char>()) + "\n" + text2;
					}
				}
				if (ZInput.GetButton("Use") || ZInput.GetButton("JoyUse"))
				{
					if (!_isHolding)
					{
						_isHolding = true;
						_holdStart = Time.time;
						ShowRing();
					}
					float num = Mathf.Clamp01((Time.time - _holdStart) / HoldDurationConfig.Value);
					if ((Object)(object)s_ringFg != (Object)null)
					{
						s_ringFg.fillAmount = num;
					}
					float num2 = 90f - num * 360f;
					float num3 = num2 * ((float)Math.PI / 180f);
					float num4 = 22.5f;
					Vector2 localStart = new Vector2(Mathf.Cos(num3), Mathf.Sin(num3)) * num4;
					s_sparkleTimer += Time.deltaTime;
					float num5 = 56f;
					while (s_sparkleTimer >= 1f / num5)
					{
						s_sparkleTimer -= 1f / num5;
						SpawnSparkle(localStart);
					}
					UpdateSparkles(Time.deltaTime);
					if (!(Time.time - _holdStart >= HoldDurationConfig.Value))
					{
						return;
					}
					_isHolding = false;
					HideRing();
					if ((Object)(object)Minimap.instance != (Object)null)
					{
						Vector3 position = hoverObject.transform.position;
						bool flag = HasPinAtPositionWithName(position, text);
						ShowCenterMessageCompat(flag ? "Already Marked" : "Location Pinned");
						if (!flag)
						{
							AddPinCompat(position, val, text, showName: true, isChecked: false, 0L);
						}
					}
				}
				else
				{
					CancelHold();
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[QuickPin] error: {arg}");
			}
		}

		private static void ShowRing()
		{
			if ((Object)(object)s_ringRoot != (Object)null)
			{
				s_ringRoot.SetActive(true);
			}
			if ((Object)(object)s_ringFg != (Object)null)
			{
				s_ringFg.fillAmount = 0f;
			}
			s_sparkleTimer = 0f;
		}

		private static void HideRing()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)s_ringRoot != (Object)null)
			{
				s_ringRoot.SetActive(false);
			}
			if ((Object)(object)s_ringRoot != (Object)null)
			{
				s_ringRoot.transform.localScale = Vector3.one;
			}
			if ((Object)(object)s_ringFg != (Object)null)
			{
				s_ringFg.fillAmount = 0f;
			}
			for (int i = 0; i < s_sparkles.Count; i++)
			{
				if (Object.op_Implicit((Object)(object)s_sparkles[i]?.rt))
				{
					Object.Destroy((Object)(object)((Component)s_sparkles[i].rt).gameObject);
				}
			}
			s_sparkles.Clear();
		}

		private static void SpawnSparkle(Vector2 localStart)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if (!((Object)(object)s_ringRoot == (Object)null))
			{
				GameObject val = new GameObject("Sparkle");
				val.transform.SetParent(s_ringRoot.transform, false);
				RectTransform val2 = val.AddComponent<RectTransform>();
				Vector2 val3 = default(Vector2);
				((Vector2)(ref val3))..ctor(0.5f, 0.5f);
				val2.pivot = val3;
				Vector2 anchorMin = (val2.anchorMax = val3);
				val2.anchorMin = anchorMin;
				float num = Random.Range(-2f, 2f);
				val2.anchoredPosition = localStart + new Vector2(num, num);
				Image val5 = val.AddComponent<Image>();
				((Graphic)val5).raycastTarget = false;
				Image obj = s_ringFg;
				val5.sprite = ((obj != null) ? obj.sprite : null);
				float num2 = Random.Range(3f, 6f);
				val2.sizeDelta = new Vector2(num2, num2);
				Color val6 = default(Color);
				((Color)(ref val6))..ctor(1f, 1f, 0.85f, 1f);
				((Graphic)val5).color = val6;
				Sparkle item = new Sparkle
				{
					rt = val2,
					img = val5,
					vel = new Vector2(Random.Range(-14f, 14f), Random.Range(-44f, -64f)),
					t = 0f,
					life = Random.Range(0.3f, 0.5f),
					startSize = num2,
					startColor = val6
				};
				s_sparkles.Add(item);
			}
		}

		private static void UpdateSparkles(float dt)
		{
			//IL_008f: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			if (s_sparkles.Count == 0)
			{
				return;
			}
			for (int num = s_sparkles.Count - 1; num >= 0; num--)
			{
				Sparkle sparkle = s_sparkles[num];
				sparkle.t += dt;
				if (sparkle.t >= sparkle.life)
				{
					if (Object.op_Implicit((Object)(object)sparkle.rt))
					{
						Object.Destroy((Object)(object)((Component)sparkle.rt).gameObject);
					}
					s_sparkles.RemoveAt(num);
				}
				else
				{
					sparkle.vel += new Vector2(0f, -120f) * dt;
					if (Object.op_Implicit((Object)(object)sparkle.rt))
					{
						RectTransform rt = sparkle.rt;
						rt.anchoredPosition += sparkle.vel * dt;
						float num2 = 1f - sparkle.t / sparkle.life;
						float num3 = Mathf.Max(0.5f, sparkle.startSize * (0.85f + 0.15f * num2));
						sparkle.rt.sizeDelta = new Vector2(num3, num3);
						if (Object.op_Implicit((Object)(object)sparkle.img))
						{
							Color startColor = sparkle.startColor;
							startColor.a = 0.2f + 0.8f * num2;
							((Graphic)sparkle.img).color = startColor;
						}
					}
					s_sparkles[num] = sparkle;
				}
			}
		}
	}

	[HarmonyPatch(typeof(Pickable), "Interact")]
	public static class PickableInteractPatch
	{
		[HarmonyPrefix]
		public static bool Prefix(Pickable __instance, Humanoid character, bool repeat, bool alt, ref bool __result)
		{
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(component.GetZDO().GetPrefab());
			string text = (Object.op_Implicit((Object)(object)prefab) ? ((Object)prefab).name : null);
			if (text == null || !AllowedPrefabIds.ContainsKey(text))
			{
				return true;
			}
			if (_manualPickFlag && (Object)(object)__instance == (Object)(object)_manualPickable)
			{
				_manualPickFlag = false;
				_manualPickable = null;
				__result = true;
				return true;
			}
			__result = false;
			return false;
		}
	}

	[HarmonyPatch(typeof(Teleport), "Interact")]
	public static class TeleportInteractPatch
	{
		[HarmonyPrefix]
		public static bool Prefix(Teleport __instance, Humanoid character, bool hold, bool alt, ref bool __result)
		{
			if (!EnableDungeonEntrancesConfig.Value)
			{
				return true;
			}
			if (_manualTeleportFlag && (Object)(object)__instance == (Object)(object)_manualTeleport)
			{
				_manualTeleportFlag = false;
				_manualTeleport = null;
				__result = true;
				return true;
			}
			if (ZInput.GetButton("Use") || ZInput.GetButton("JoyUse"))
			{
				__result = false;
				return false;
			}
			return true;
		}
	}

	[Serializable]
	[CompilerGenerated]
	private sealed class <>c
	{
		public static readonly <>c <>9 = new <>c();

		public static ConsoleEvent <>9__34_0;

		public static ConsoleEvent <>9__34_1;

		public static ConsoleEvent <>9__34_2;

		internal void <RegisterConsoleCommands>b__34_0(ConsoleEventArgs args)
		{
			if (args.Length < 2)
			{
				args.Context.AddString("Current hold hint: " + (ShowHoldHintConfig.Value ? "on" : "off"));
				return;
			}
			string text = args.Args[1].ToLower();
			if (text == "on" || text == "off")
			{
				ShowHoldHintConfig.Value = text == "on";
				args.Context.AddString("Hold hint set to: " + text);
			}
			else
			{
				args.Context.AddString("Invalid value. Use 'on' or 'off'");
			}
		}

		internal void <RegisterConsoleCommands>b__34_1(ConsoleEventArgs args)
		{
			int result;
			if (args.Length < 2)
			{
				args.Context.AddString($"Current hold duration: {(int)(HoldDurationConfig.Value * 1000f)} ms");
			}
			else if (int.TryParse(args.Args[1], out result))
			{
				if (result >= 100 && result <= 10000)
				{
					HoldDurationConfig.Value = (float)result / 1000f;
					args.Context.AddString($"Hold duration set to: {result} ms");
				}
				else
				{
					args.Context.AddString("Value must be between 100 and 10000 ms");
				}
			}
			else
			{
				args.Context.AddString("Invalid value. Please enter a number between 100 and 10000");
			}
		}

		internal void <RegisterConsoleCommands>b__34_2(ConsoleEventArgs args)
		{
			if (args.Length < 2)
			{
				args.Context.AddString("Dungeon entrances: " + (EnableDungeonEntrancesConfig.Value ? "enabled" : "disabled"));
				return;
			}
			string text = args.Args[1].ToLower();
			if (text == "on" || text == "off")
			{
				EnableDungeonEntrancesConfig.Value = text == "on";
				args.Context.AddString("Dungeon entrance pinning: " + text);
			}
			else
			{
				args.Context.AddString("Invalid value. Use 'on' or 'off'");
			}
		}
	}

	internal static ManualLogSource Log;

	private const string PluginVersionString = "1.1.0";

	private static readonly Version CurrentVersion = new Version("1.1.0");

	private static ConfigEntry<float> HoldDurationConfig;

	private static ConfigEntry<bool> ShowHoldHintConfig;

	private static ConfigEntry<bool> EnableDungeonEntrancesConfig;

	private static string ItemListFilePath;

	private static string ConfigFilePath;

	private static Dictionary<string, PinItem> AllowedPrefabIds = new Dictionary<string, PinItem>(StringComparer.OrdinalIgnoreCase);

	private static Dictionary<string, PinItem> AllowedPortalIds = new Dictionary<string, PinItem>(StringComparer.OrdinalIgnoreCase);

	private static bool _manualPickFlag;

	private static Pickable _manualPickable;

	private static Pickable _holdPickable;

	private static float _holdStart;

	private static bool _manualTeleportFlag;

	private static Teleport _manualTeleport;

	private static Teleport _holdTeleport;

	private static float _holdTeleportStart;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Log.LogInfo((object)"QuickPin loaded.");
		string boundUseKeyStringForConfig = GetBoundUseKeyStringForConfig();
		HoldDurationConfig = ((BaseUnityPlugin)this).Config.Bind<float>("General", "HoldDuration", 1f, "How long (in seconds) you must hold " + boundUseKeyStringForConfig + " to tag a deposit/item.");
		ShowHoldHintConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowHoldHint", true, "Show the '[" + boundUseKeyStringForConfig + "] Tag Location' hover text. If false, only the progress bar is shown.");
		EnableDungeonEntrancesConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableDungeonEntrances", true, "Enable pinning of dungeon entrances (burial chambers, crypts, caves, etc.)");
		ItemListFilePath = Path.Combine(Paths.ConfigPath, "FrostJack.QuickPin_Items.xml");
		ConfigFilePath = Path.Combine(Paths.ConfigPath, "FrostJack.QuickPin.cfg");
		LoadOrCreateItemList();
		RegisterConsoleCommands();
		_harmony = new Harmony("FrostJack.QuickPin");
		_harmony.PatchAll();
		Log.LogInfo((object)"Harmony patches applied.");
	}

	private void OnDestroy()
	{
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		UpdateCrosshairPatch.CleanupStatic();
		Log.LogInfo((object)"QuickPin OnDestroy: Unpatched and cleaned up.");
	}

	private static string GetBoundUseKeyStringCore()
	{
		try
		{
			if (ZInput.instance != null)
			{
				string text = (ZInput.IsGamepadActive() ? ZInput.instance.GetBoundKeyString("JoyUse", false) : ZInput.instance.GetBoundKeyString("Use", false));
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
		}
		catch
		{
		}
		return "E";
	}

	private static string GetBoundUseKeyStringForHover()
	{
		return GetBoundUseKeyStringCore();
	}

	private static string GetBoundUseKeyStringForConfig()
	{
		return GetBoundUseKeyStringCore();
	}

	internal static string BuildPinHint()
	{
		string boundUseKeyStringForHover = GetBoundUseKeyStringForHover();
		return "[<color=yellow>HOLD " + boundUseKeyStringForHover + "</color>] Tag Location";
	}

	internal static void ShowCenterMessageCompat(string text)
	{
		try
		{
			if ((Object)(object)MessageHud.instance == (Object)null)
			{
				return;
			}
			MessageHud instance = MessageHud.instance;
			Type type = ((object)instance).GetType();
			MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "ShowMessage")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length >= 2 && parameters[0].ParameterType == typeof(MessageType) && parameters[1].ParameterType == typeof(string))
				{
					object[] array = new object[parameters.Length];
					array[0] = (object)(MessageType)2;
					array[1] = text;
					for (int j = 2; j < parameters.Length; j++)
					{
						Type parameterType = parameters[j].ParameterType;
						array[j] = (parameterType.IsValueType ? Activator.CreateInstance(parameterType) : null);
					}
					methodInfo.Invoke(instance, array);
					break;
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogWarning((object)("[QuickPin] ShowCenterMessageCompat failed: " + ex.Message));
			}
		}
	}

	internal static void AddPinCompat(Vector3 pos, PinType type, string name, bool showName, bool isChecked, long ownerId)
	{
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if ((Object)(object)Minimap.instance == (Object)null)
			{
				return;
			}
			Minimap instance = Minimap.instance;
			Type type2 = ((object)instance).GetType();
			MethodInfo methodInfo = null;
			MethodInfo[] methods = type2.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (!(methodInfo2.Name != "AddPin"))
				{
					ParameterInfo[] parameters = methodInfo2.GetParameters();
					if (parameters.Length >= 3 && parameters[0].ParameterType == typeof(Vector3) && parameters[2].ParameterType == typeof(string) && parameters[1].ParameterType.IsEnum && parameters[1].ParameterType.Name.Contains("PinType"))
					{
						methodInfo = methodInfo2;
						break;
					}
				}
			}
			if (methodInfo == null)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)"[QuickPin] AddPinCompat: No suitable Minimap.AddPin overload found");
				}
				return;
			}
			ParameterInfo[] parameters2 = methodInfo.GetParameters();
			object[] array = new object[parameters2.Length];
			for (int j = 0; j < parameters2.Length; j++)
			{
				Type parameterType = parameters2[j].ParameterType;
				switch (j)
				{
				case 0:
					array[j] = pos;
					continue;
				case 1:
					array[j] = type;
					continue;
				case 2:
					array[j] = name;
					continue;
				}
				if (parameterType == typeof(bool))
				{
					array[j] = j switch
					{
						4 => isChecked, 
						3 => showName, 
						_ => false, 
					};
				}
				else if (parameterType == typeof(long))
				{
					array[j] = ownerId;
				}
				else if (parameterType == typeof(string))
				{
					array[j] = string.Empty;
				}
				else if (parameterType.IsValueType)
				{
					array[j] = Activator.CreateInstance(parameterType);
				}
				else
				{
					array[j] = null;
				}
			}
			methodInfo.Invoke(instance, array);
		}
		catch (Exception ex)
		{
			ManualLogSource log2 = Log;
			if (log2 != null)
			{
				log2.LogWarning((object)("[QuickPin] AddPinCompat failed: " + ex.Message));
			}
		}
	}

	internal static string GetDungeonEntranceName(Teleport teleport)
	{
		if ((Object)(object)teleport == (Object)null)
		{
			return "Dungeon Entrance";
		}
		Transform val = ((Component)teleport).transform;
		while ((Object)(object)val != (Object)null)
		{
			string text = ((Object)val).name;
			if (text.EndsWith("(Clone)"))
			{
				text = text.Substring(0, text.Length - 7);
			}
			if (AllowedPortalIds.TryGetValue(text, out var value))
			{
				return value.Name;
			}
			val = val.parent;
		}
		return (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !((Character)Player.m_localPlayer).InInterior()) ? "Dungeon Entrance" : "Dungeon Exit";
	}

	internal static PinType GetDungeonEntrancePinType(Teleport teleport)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)teleport == (Object)null)
		{
			return (PinType)6;
		}
		Transform val = ((Component)teleport).transform;
		while ((Object)(object)val != (Object)null)
		{
			string text = ((Object)val).name;
			if (text.EndsWith("(Clone)"))
			{
				text = text.Substring(0, text.Length - 7);
			}
			if (AllowedPortalIds.TryGetValue(text, out var value))
			{
				return value.PinType;
			}
			val = val.parent;
		}
		return (PinType)6;
	}

	private static bool IsMajorBump(Version fileVersion)
	{
		if (fileVersion == null)
		{
			return true;
		}
		return fileVersion.Major != CurrentVersion.Major || fileVersion.Minor != CurrentVersion.Minor;
	}

	private static void BackupFile(string path)
	{
		if (File.Exists(path))
		{
			string text = path + ".bak";
			if (File.Exists(text))
			{
				File.Delete(text);
			}
			File.Move(path, text);
		}
	}

	private static Version GetFileVersion(XDocument doc)
	{
		try
		{
			XElement root = doc.Root;
			object obj;
			if (root == null)
			{
				obj = null;
			}
			else
			{
				XAttribute obj2 = root.Attribute(XName.op_Implicit("version"));
				obj = ((obj2 != null) ? obj2.Value : null);
			}
			string text = (string)obj;
			if (!string.IsNullOrEmpty(text))
			{
				return new Version(text);
			}
		}
		catch
		{
		}
		return null;
	}

	private void LoadOrCreateItemList()
	{
		//IL_06a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_06a8: Expected O, but got Unknown
		//IL_06af: Unknown result type (might be due to invalid IL or missing references)
		//IL_06b5: Expected O, but got Unknown
		//IL_06bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_06c2: Expected O, but got Unknown
		//IL_06c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_06cf: Expected O, but got Unknown
		//IL_06d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_06dc: Expected O, but got Unknown
		//IL_06e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_06e9: Expected O, but got Unknown
		//IL_06f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_06f6: Expected O, but got Unknown
		//IL_06fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0703: Expected O, but got Unknown
		//IL_070a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0710: Expected O, but got Unknown
		//IL_0718: Unknown result type (might be due to invalid IL or missing references)
		//IL_071e: Expected O, but got Unknown
		//IL_0726: Unknown result type (might be due to invalid IL or missing references)
		//IL_072c: Expected O, but got Unknown
		//IL_0734: Unknown result type (might be due to invalid IL or missing references)
		//IL_073a: Expected O, but got Unknown
		//IL_0742: Unknown result type (might be due to invalid IL or missing references)
		//IL_0748: Expected O, but got Unknown
		//IL_0750: Unknown result type (might be due to invalid IL or missing references)
		//IL_0756: Expected O, but got Unknown
		//IL_075e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0764: Expected O, but got Unknown
		//IL_076c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0772: Expected O, but got Unknown
		//IL_077a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0780: Expected O, but got Unknown
		//IL_0788: Unknown result type (might be due to invalid IL or missing references)
		//IL_078e: Expected O, but got Unknown
		//IL_0796: Unknown result type (might be due to invalid IL or missing references)
		//IL_079c: Expected O, but got Unknown
		//IL_07a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_07aa: Expected O, but got Unknown
		//IL_07b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_07b8: Expected O, but got Unknown
		//IL_07c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_07c6: Expected O, but got Unknown
		//IL_07ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_07d4: Expected O, but got Unknown
		//IL_07dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_07e2: Expected O, but got Unknown
		//IL_07ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_07f0: Expected O, but got Unknown
		//IL_07fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0803: Expected O, but got Unknown
		//IL_080b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0811: Expected O, but got Unknown
		//IL_0819: Unknown result type (might be due to invalid IL or missing references)
		//IL_081f: Expected O, but got Unknown
		//IL_0827: Unknown result type (might be due to invalid IL or missing references)
		//IL_082d: Expected O, but got Unknown
		//IL_0835: Unknown result type (might be due to invalid IL or missing references)
		//IL_083b: Expected O, but got Unknown
		//IL_0843: Unknown result type (might be due to invalid IL or missing references)
		//IL_0849: Expected O, but got Unknown
		//IL_0856: Unknown result type (might be due to invalid IL or missing references)
		//IL_085c: Expected O, but got Unknown
		//IL_085c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0862: Expected O, but got Unknown
		//IL_0862: Unknown result type (might be due to invalid IL or missing references)
		//IL_0869: Expected O, but got Unknown
		//IL_0899: Unknown result type (might be due to invalid IL or missing references)
		//IL_08a0: Expected O, but got Unknown
		//IL_08e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_08ee: Expected O, but got Unknown
		//IL_090f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0916: Expected O, but got Unknown
		//IL_0aa2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0aa8: Expected O, but got Unknown
		//IL_0ab6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0abc: Expected O, but got Unknown
		//IL_0acf: Unknown result type (might be due to invalid IL or missing references)
		//IL_0ad5: Expected O, but got Unknown
		//IL_0ae6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0aec: Expected O, but got Unknown
		//IL_0aec: Unknown result type (might be due to invalid IL or missing references)
		//IL_0af6: Expected O, but got Unknown
		//IL_0b79: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b7f: Expected O, but got Unknown
		//IL_0b8d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b93: Expected O, but got Unknown
		//IL_0ba6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0bac: Expected O, but got Unknown
		//IL_0bbd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0bc3: Expected O, but got Unknown
		//IL_0bc3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0bcd: Expected O, but got Unknown
		List<(string, string, int)> list = new List<(string, string, int)>
		{
			("Pickable_Mushroom", "Mushroom", 3),
			("RaspberryBush", "Raspberry bush", 3),
			("BlueberryBush", "Blueberry Bush", 3),
			("Pickable_Thistle", "Thistle", 3),
			("Pickable_Mushroom_yellow", "Glowing Mushroom", 3),
			("Pickable_SeedCarrot", "Carrot Seeds", 3),
			("rock4_copper", "Copper Deposit", 3),
			("rock4_copper_frac", "Copper Deposit Damaged", 3),
			("MineRock_Tin", "Tin Deposit", 3),
			("Spawner_GreydwarfNest", "Greydwarf Nest", 3),
			("Spawner_DraugrPile", "Draugr Pile", 3),
			("BonePileSpawner", "Skeleton Spawner", 3),
			("GuckSack", "GuckSack", 3),
			("GuckSack_small", "GuckSack", 3),
			("Pickable_SeedTurnip", "Turnip Seeds", 3),
			("mudpile_beacon", "Scrap Pile", 3),
			("mudpile_frac", "Scrap Pile", 3),
			("sunken_crypt_gate", "Sunken Crypt", 6),
			("silvervein", "Silvervein", 3),
			("silvervein_frac", "Silvervein Damaged", 3),
			("MineRock_Obsidian", "Obsidian Rock", 3),
			("Pickable_DragonEgg", "Dragon Egg", 3),
			("CloudberryBush", "Cloudberry Bush", 3),
			("Pickable_Tar", "Tar", 3),
			("Pickable_TarBig", "Tar", 3),
			("Pickable_Flax_Wild", "Flax", 3),
			("Pickable_Barley_Wild", "Barley", 3),
			("giant_skull", "Giant Skull", 3),
			("giant_skull_frac", "Giant Skull", 3),
			("giant_ribs", "Giant Ribs", 3),
			("giant_ribs_frac", "Giant Ribs", 3),
			("Skull1", "Soft Tissue", 3),
			("Skull2", "Soft Tissue", 3),
			("giant_helmet1_destruction", "Ancient Armor", 3),
			("giant_helmet2_destruction", "Ancient Armor", 3),
			("giant_helmet1", "Ancient Armor", 3),
			("giant_helmet2", "Ancient Armor", 3),
			("giant_sword1_destruction", "Ancient Sword", 3),
			("giant_sword2_destruction", "Ancient Sword", 3),
			("giant_sword1", "Ancient Sword", 3),
			("giant_sword2", "Ancient Sword", 3),
			("Pickable_Mushroom_Magecap", "Magecap", 3),
			("Pickable_Mushroom_JotunPuffs", "Jotun Puffs", 3),
			("YggdrasilRoot", "Ancient Roots", 3),
			("giant_brain", "Soft Tissue", 3),
			("giant_brain_frac", "Soft Tissue", 3),
			("UnstableLavaRock", "Lava Rock", 3),
			("Pickable_SmokePuff", "SmokePuff", 3),
			("LeviathanLava", "Flametal vein", 3),
			("Pickable_Fiddlehead", "Fiddle head", 3),
			("vineash", "Ashvine", 3),
			("Pickable_SulfurRock", "Sulfur Rock", 3),
			("Spawner_CharredStone", "Monument of Torment", 3),
			("Spawner_CharredStone_Elite", "Monument of Torment Elite", 3)
		};
		List<(string, string, int)> list2 = new List<(string, string, int)>
		{
			("crypt2", "Burial Chambers", 6),
			("crypt3", "Burial Chambers", 6),
			("crypt4", "Burial Chambers", 6),
			("hildir_cave", "Frost Cave", 6),
			("Mistlands_DvergrTownEntrance1", "Infested Mines", 6),
			("Mistlands_DvergrTownEntrance2", "Infested Mines", 6),
			("trollcave02", "Troll Cave", 6)
		};
		bool flag = false;
		Version version = null;
		if (File.Exists(ItemListFilePath))
		{
			try
			{
				XDocument doc = XDocument.Load(ItemListFilePath);
				version = GetFileVersion(doc);
				if (IsMajorBump(version))
				{
					flag = true;
					Log.LogInfo((object)string.Format("[QuickPin] Major version change detected: {0} → {1}. Resetting configs.", version?.ToString() ?? "unknown", CurrentVersion));
				}
			}
			catch
			{
				flag = true;
				Log.LogInfo((object)"[QuickPin] Invalid config file format. Resetting.");
			}
		}
		if (flag)
		{
			BackupFile(ItemListFilePath);
			BackupFile(ConfigFilePath);
			if (File.Exists(ItemListFilePath))
			{
				File.Delete(ItemListFilePath);
			}
			if (File.Exists(ConfigFilePath))
			{
				File.Delete(ConfigFilePath);
			}
		}
		XDocument val = (XDocument)(File.Exists(ItemListFilePath) ? ((object)XDocument.Load(ItemListFilePath)) : ((object)new XDocument(new object[1] { (object)new XElement(XName.op_Implicit("QuickPinConfig"), new object[32]
		{
			(object)new XAttribute(XName.op_Implicit("version"), (object)"1.1.0"),
			(object)new XComment(" CONFIG VERSION: 1.1.0 "),
			(object)new XComment(" This file may be reset on major version updates (e.g., 1.0.x to 1.1.x). "),
			(object)new XComment(" A backup is saved as .bak in this folder if your customizations were lost. "),
			(object)new XComment(""),
			(object)new XComment(" === PIN TYPE REFERENCE ==="),
			(object)new XComment(" 0 = Campfire / Fireplace"),
			(object)new XComment(" 1 = House / Base"),
			(object)new XComment(" 2 = Hammer / Crafting"),
			(object)new XComment(" 3 = Dot / Sphere (default for items)"),
			(object)new XComment(" 4 = Death marker (Skull & Crossbones)"),
			(object)new XComment(" 5 = Bed (Spawn point)"),
			(object)new XComment(" 6 = Portal (T-shape / Archway, default for portals)"),
			(object)new XComment(" 7 = Shout (Chat bubble)"),
			(object)new XComment(" 8 = None (Invisible)"),
			(object)new XComment(" 9 = Boss (Red boss location marker)"),
			(object)new XComment(" 10 = Player (Arrow/triangle)"),
			(object)new XComment(" 11 = RandomEvent (Red pulsing circle for base raids)"),
			(object)new XComment(" 12 = Ping (Temporary player map ping)"),
			(object)new XComment(" 13 = EventArea (Localized event area marker)"),
			(object)new XComment(""),
			(object)new XComment(" === ITEMS SECTION ==="),
			(object)new XComment(" Add items as needed below, following the same structure as the examples. "),
			(object)new XComment(" You can enable or disable items by setting enabled=\"true\" or enabled=\"false\". "),
			(object)new XComment(" The pinType attribute controls which minimap icon is used (default: 3 for items). "),
			(object)new XElement(XName.op_Implicit("items")),
			(object)new XComment(""),
			(object)new XComment(" === PORTALS SECTION ==="),
			(object)new XComment(" Dungeon entrances (Teleport components) are configured here. "),
			(object)new XComment(" The id should match the room prefab name (e.g., crypt2, trollcave02). "),
			(object)new XComment(" The pinType attribute controls which minimap icon is used (default: 6 for portals). "),
			(object)new XElement(XName.op_Implicit("portals"))
		}) })));
		XElement val2 = val.Root;
		if (val2 == null)
		{
			val2 = new XElement(XName.op_Implicit("QuickPinConfig"));
			((XContainer)val).Add((object)val2);
		}
		XElement val3 = ((XContainer)val2).Element(XName.op_Implicit("items"));
		XElement val4 = ((XContainer)val2).Element(XName.op_Implicit("portals"));
		if (val3 == null)
		{
			val3 = new XElement(XName.op_Implicit("items"));
			((XContainer)val2).Add((object)val3);
		}
		if (val4 == null)
		{
			val4 = new XElement(XName.op_Implicit("portals"));
			((XContainer)val2).Add((object)val4);
		}
		HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		HashSet<string> hashSet2 = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		foreach (XElement item in ((XContainer)val3).Elements(XName.op_Implicit("item")))
		{
			XAttribute obj2 = item.Attribute(XName.op_Implicit("id"));
			string text = ((obj2 == null) ? null : obj2.Value?.Trim());
			if (!string.IsNullOrEmpty(text))
			{
				hashSet.Add(text);
			}
		}
		foreach (XElement item2 in ((XContainer)val4).Elements(XName.op_Implicit("item")))
		{
			XAttribute obj3 = item2.Attribute(XName.op_Implicit("id"));
			string text2 = ((obj3 == null) ? null : obj3.Value?.Trim());
			if (!string.IsNullOrEmpty(text2))
			{
				hashSet2.Add(text2);
			}
		}
		bool flag2 = false;
		foreach (var (text3, text4, num) in list)
		{
			if (!hashSet.Contains(text3))
			{
				((XContainer)val3).Add((object)new XElement(XName.op_Implicit("item"), new object[4]
				{
					(object)new XAttribute(XName.op_Implicit("id"), (object)text3),
					(object)new XAttribute(XName.op_Implicit("name"), (object)text4),
					(object)new XAttribute(XName.op_Implicit("pinType"), (object)num),
					(object)new XAttribute(XName.op_Implicit("enabled"), (object)"true")
				}));
				flag2 = true;
			}
		}
		foreach (var (text5, text6, num2) in list2)
		{
			if (!hashSet2.Contains(text5))
			{
				((XContainer)val4).Add((object)new XElement(XName.op_Implicit("item"), new object[4]
				{
					(object)new XAttribute(XName.op_Implicit("id"), (object)text5),
					(object)new XAttribute(XName.op_Implicit("name"), (object)text6),
					(object)new XAttribute(XName.op_Implicit("pinType"), (object)num2),
					(object)new XAttribute(XName.op_Implicit("enabled"), (object)"true")
				}));
				flag2 = true;
			}
		}
		if (flag2)
		{
			val.Save(ItemListFilePath);
			Log.LogInfo((object)("Updated config at " + ItemListFilePath + " with missing items/portals."));
		}
		else
		{
			Log.LogInfo((object)("Config at " + ItemListFilePath + " already up-to-date."));
		}
		AllowedPrefabIds.Clear();
		AllowedPortalIds.Clear();
		try
		{
			foreach (XElement item3 in ((XContainer)val3).Elements(XName.op_Implicit("item")))
			{
				XAttribute obj4 = item3.Attribute(XName.op_Implicit("id"));
				string text7 = ((obj4 == null) ? null : obj4.Value?.Trim());
				XAttribute obj5 = item3.Attribute(XName.op_Implicit("name"));
				string name = ((obj5 == null) ? null : obj5.Value?.Trim()) ?? "";
				XAttribute obj6 = item3.Attribute(XName.op_Implicit("enabled"));
				string value = ((obj6 == null) ? null : obj6.Value?.Trim());
				bool result = true;
				if (!string.IsNullOrEmpty(value))
				{
					bool.TryParse(value, out result);
				}
				int num3 = 3;
				XAttribute obj7 = item3.Attribute(XName.op_Implicit("pinType"));
				string text8 = ((obj7 == null) ? null : obj7.Value?.Trim());
				if (!string.IsNullOrEmpty(text8) && int.TryParse(text8, out var result2))
				{
					num3 = result2;
				}
				if (!string.IsNullOrEmpty(text7) && result)
				{
					AllowedPrefabIds[text7] = new PinItem
					{
						Name = name,
						PinType = (PinType)num3
					};
				}
			}
			foreach (XElement item4 in ((XContainer)val4).Elements(XName.op_Implicit("item")))
			{
				XAttribute obj8 = item4.Attribute(XName.op_Implicit("id"));
				string text9 = ((obj8 == null) ? null : obj8.Value?.Trim());
				XAttribute obj9 = item4.Attribute(XName.op_Implicit("name"));
				string name2 = ((obj9 == null) ? null : obj9.Value?.Trim()) ?? "";
				XAttribute obj10 = item4.Attribute(XName.op_Implicit("enabled"));
				string value2 = ((obj10 == null) ? null : obj10.Value?.Trim());
				bool result3 = true;
				if (!string.IsNullOrEmpty(value2))
				{
					bool.TryParse(value2, out result3);
				}
				int num4 = 6;
				XAttribute obj11 = item4.Attribute(XName.op_Implicit("pinType"));
				string text10 = ((obj11 == null) ? null : obj11.Value?.Trim());
				if (!string.IsNullOrEmpty(text10) && int.TryParse(text10, out var result4))
				{
					num4 = result4;
				}
				if (!string.IsNullOrEmpty(text9) && result3)
				{
					AllowedPortalIds[text9] = new PinItem
					{
						Name = name2,
						PinType = (PinType)num4
					};
				}
			}
			Log.LogInfo((object)$"Loaded {AllowedPrefabIds.Count} enabled items and {AllowedPortalIds.Count} enabled portals from XML config.");
		}
		catch (Exception arg)
		{
			Log.LogError((object)$"Failed to load config XML: {arg}");
		}
	}

	private void RegisterConsoleCommands()
	{
		//IL_0033: 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_002a: Expected O, but got Unknown
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Expected O, but got Unknown
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Expected O, but got Unknown
		object obj = <>c.<>9__34_0;
		if (obj == null)
		{
			ConsoleEvent val = delegate(ConsoleEventArgs args)
			{
				if (args.Length < 2)
				{
					args.Context.AddString("Current hold hint: " + (ShowHoldHintConfig.Value ? "on" : "off"));
				}
				else
				{
					string text = args.Args[1].ToLower();
					if (text == "on" || text == "off")
					{
						ShowHoldHintConfig.Value = text == "on";
						args.Context.AddString("Hold hint set to: " + text);
					}
					else
					{
						args.Context.AddString("Invalid value. Use 'on' or 'off'");
					}
				}
			};
			<>c.<>9__34_0 = val;
			obj = (object)val;
		}
		new ConsoleCommand("quickpin_showhint", "[on/off] - Toggle hold hint hover text", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		object obj2 = <>c.<>9__34_1;
		if (obj2 == null)
		{
			ConsoleEvent val2 = delegate(ConsoleEventArgs args)
			{
				int result;
				if (args.Length < 2)
				{
					args.Context.AddString($"Current hold duration: {(int)(HoldDurationConfig.Value * 1000f)} ms");
				}
				else if (int.TryParse(args.Args[1], out result))
				{
					if (result >= 100 && result <= 10000)
					{
						HoldDurationConfig.Value = (float)result / 1000f;
						args.Context.AddString($"Hold duration set to: {result} ms");
					}
					else
					{
						args.Context.AddString("Value must be between 100 and 10000 ms");
					}
				}
				else
				{
					args.Context.AddString("Invalid value. Please enter a number between 100 and 10000");
				}
			};
			<>c.<>9__34_1 = val2;
			obj2 = (object)val2;
		}
		new ConsoleCommand("quickpin_holdduration", "[milliseconds] - Set hold duration in ms (e.g. 1500)", (ConsoleEvent)obj2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		object obj3 = <>c.<>9__34_2;
		if (obj3 == null)
		{
			ConsoleEvent val3 = delegate(ConsoleEventArgs args)
			{
				if (args.Length < 2)
				{
					args.Context.AddString("Dungeon entrances: " + (EnableDungeonEntrancesConfig.Value ? "enabled" : "disabled"));
				}
				else
				{
					string text = args.Args[1].ToLower();
					if (text == "on" || text == "off")
					{
						EnableDungeonEntrancesConfig.Value = text == "on";
						args.Context.AddString("Dungeon entrance pinning: " + text);
					}
					else
					{
						args.Context.AddString("Invalid value. Use 'on' or 'off'");
					}
				}
			};
			<>c.<>9__34_2 = val3;
			obj3 = (object)val3;
		}
		new ConsoleCommand("quickpin_dungeons", "[on/off] - Toggle dungeon entrance pinning", (ConsoleEvent)obj3, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private void Update()
	{
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			bool flag = ZInput.GetButtonDown("Use") || ZInput.GetButtonDown("JoyUse");
			bool flag2 = ZInput.GetButtonUp("Use") || ZInput.GetButtonUp("JoyUse");
			GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
			if ((Object)(object)hoverObject != (Object)null && EnableDungeonEntrancesConfig.Value)
			{
				Teleport componentInParent = hoverObject.GetComponentInParent<Teleport>();
				if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.m_targetPoint != (Object)null)
				{
					if (flag)
					{
						_holdTeleportStart = Time.time;
						_holdTeleport = componentInParent;
					}
					if (!flag2 || !((Object)(object)_holdTeleport != (Object)null))
					{
						return;
					}
					float num = Time.time - _holdTeleportStart;
					if (num < HoldDurationConfig.Value)
					{
						_manualTeleportFlag = true;
						_manualTeleport = _holdTeleport;
						if ((Object)(object)_holdTeleport != (Object)null && (Object)(object)localPlayer != (Object)null)
						{
							_holdTeleport.Interact((Humanoid)(object)localPlayer, false, false);
						}
					}
					_holdTeleport = null;
					return;
				}
			}
			Pickable val = null;
			if ((Object)(object)hoverObject != (Object)null)
			{
				try
				{
					val = hoverObject.GetComponentInParent<Pickable>();
				}
				catch
				{
					val = null;
				}
			}
			string text = null;
			if ((Object)(object)val != (Object)null)
			{
				ZNetView component = ((Component)val).GetComponent<ZNetView>();
				ZDO val2 = (((Object)(object)component != (Object)null) ? component.GetZDO() : null);
				if (val2 != null && (Object)(object)ZNetScene.instance != (Object)null)
				{
					GameObject prefab = ZNetScene.instance.GetPrefab(val2.GetPrefab());
					text = (Object.op_Implicit((Object)(object)prefab) ? ((Object)prefab).name : null);
				}
			}
			bool flag3 = text != null && AllowedPrefabIds.ContainsKey(text);
			if (flag && flag3)
			{
				_holdStart = Time.time;
				_holdPickable = val;
			}
			if (!(flag2 && flag3) || !((Object)(object)_holdPickable != (Object)null))
			{
				return;
			}
			float num2 = Time.time - _holdStart;
			if (num2 < HoldDurationConfig.Value)
			{
				_manualPickFlag = true;
				_manualPickable = _holdPickable;
				if ((Object)(object)_holdPickable != (Object)null && (Object)(object)localPlayer != (Object)null)
				{
					_holdPickable.Interact((Humanoid)(object)localPlayer, false, false);
				}
			}
			_holdPickable = null;
		}
		catch (Exception arg)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogError((object)$"[QuickPin] Update error: {arg}");
			}
		}
	}
}