Decompiled source of Gatherer v1.3.1

ValheimGatherer.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;
using UnityEngine.UI;
using ValheimGatherer.Configuration;
using ValheimGatherer.Core;
using ValheimGatherer.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("ValheimGatherer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.1.0")]
[assembly: AssemblyInformationalVersion("1.3.1+5d9bb984594ad6806304be2346cd041a768f0cf9")]
[assembly: AssemblyProduct("ValheimGatherer")]
[assembly: AssemblyTitle("ValheimGatherer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 ValheimGatherer
{
	[BepInPlugin("com.watchdoge.valheim.gatherer", "Gatherer", "1.3.1")]
	public class GathererPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.watchdoge.valheim.gatherer";

		public const string PluginName = "Gatherer";

		public const string PluginVersion = "1.3.1";

		private Harmony? _harmony;

		public static GathererConfig? ModConfig { get; private set; }

		private void Awake()
		{
			ModConfig = new GathererConfig(((BaseUnityPlugin)this).Config);
			GathererManager.Instance.Initialize(ModConfig, ((BaseUnityPlugin)this).Logger);
			((Component)this).gameObject.AddComponent<ProximityScanner>();
			GathererInGameUI.Attach(((Component)this).gameObject);
			_harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "com.watchdoge.valheim.gatherer");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Gatherer v1.3.1 loaded successfully.");
		}

		private void OnDestroy()
		{
			ResourcePinPresentation.Reset();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace ValheimGatherer.UI
{
	public class GathererInGameUI : MonoBehaviour
	{
		private static GathererInGameUI? _instance;

		private bool _isOpen;

		private Rect _windowRect = new Rect(80f, 80f, 720f, 520f);

		private Vector2 _scrollPos = Vector2.zero;

		private int _activeTab;

		private GUIStyle? _winStyle;

		private GUIStyle? _headerStyle;

		private GUIStyle? _tabStyle;

		private GUIStyle? _tabActiveStyle;

		private GUIStyle? _sectionStyle;

		private GUIStyle? _toggleStyle;

		private GUIStyle? _labelStyle;

		private GUIStyle? _btnStyle;

		private Texture2D? _bgTexture;

		private Texture2D? _tabActiveTexture;

		public static GathererInGameUI? Instance => _instance;

		public static bool IsMenuOpen
		{
			get
			{
				if ((Object)(object)_instance != (Object)null)
				{
					return _instance._isOpen;
				}
				return false;
			}
		}

		public static void Attach(GameObject root)
		{
			if ((Object)(object)_instance == (Object)null)
			{
				_instance = root.AddComponent<GathererInGameUI>();
			}
		}

		private void Awake()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			_instance = this;
			_windowRect = new Rect((float)Mathf.Max(20, (Screen.width - 720) / 2), (float)Mathf.Max(20, (Screen.height - 520) / 2), 720f, 520f);
		}

		private void Update()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			GathererConfig config = GathererManager.Instance.Config;
			if (config != null)
			{
				if (Input.GetKeyDown(config.ToggleUiKey.Value))
				{
					ToggleMenu();
				}
				if (_isOpen && Input.GetKeyDown((KeyCode)27))
				{
					_isOpen = false;
					TakeInputFocus(focus: false);
				}
				if (_isOpen)
				{
					ZCursor.LockState = (CursorLockMode)0;
					ZCursor.Show();
					Cursor.lockState = (CursorLockMode)0;
					Cursor.visible = true;
				}
			}
		}

		public void ToggleMenu()
		{
			_isOpen = !_isOpen;
			TakeInputFocus(_isOpen);
		}

		private void TakeInputFocus(bool focus)
		{
			if (focus)
			{
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
			else if ((Object)(object)Player.m_localPlayer != (Object)null && !Menu.IsVisible() && !InventoryGui.IsVisible() && !Minimap.IsOpen())
			{
				ZCursor.LockState = (CursorLockMode)1;
				ZCursor.Hide();
				Cursor.lockState = (CursorLockMode)1;
				Cursor.visible = false;
			}
		}

		private void InitStyles()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Expected O, but got Unknown
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Expected O, but got Unknown
			//IL_01dd: 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_0208: Expected O, but got Unknown
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Expected O, but got Unknown
			//IL_027b: 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_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Expected O, but got Unknown
			//IL_02d6: 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_02f5: Expected O, but got Unknown
			if (_winStyle == null)
			{
				_bgTexture = MakeSolidTexture(1, 1, new Color(0.12f, 0.14f, 0.17f, 0.96f));
				_tabActiveTexture = MakeSolidTexture(1, 1, new Color(0.24f, 0.38f, 0.52f, 1f));
				_winStyle = new GUIStyle(GUI.skin.window);
				_winStyle.normal.background = _bgTexture;
				_winStyle.normal.textColor = new Color(0.95f, 0.85f, 0.55f);
				_winStyle.fontSize = 15;
				_winStyle.fontStyle = (FontStyle)1;
				_winStyle.alignment = (TextAnchor)1;
				_winStyle.padding = new RectOffset(14, 14, 28, 14);
				_headerStyle = new GUIStyle(GUI.skin.label);
				_headerStyle.fontSize = 13;
				_headerStyle.fontStyle = (FontStyle)1;
				_headerStyle.normal.textColor = new Color(0.95f, 0.85f, 0.55f);
				_headerStyle.margin = new RectOffset(0, 0, 10, 4);
				_sectionStyle = new GUIStyle(GUI.skin.label);
				_sectionStyle.fontSize = 12;
				_sectionStyle.fontStyle = (FontStyle)1;
				_sectionStyle.normal.textColor = new Color(0.55f, 0.85f, 0.95f);
				_sectionStyle.margin = new RectOffset(0, 0, 8, 2);
				_tabStyle = new GUIStyle(GUI.skin.button);
				_tabStyle.fontSize = 12;
				_tabStyle.normal.textColor = Color.white;
				_tabStyle.fixedHeight = 28f;
				_tabActiveStyle = new GUIStyle(_tabStyle);
				_tabActiveStyle.normal.background = _tabActiveTexture;
				_tabActiveStyle.fontStyle = (FontStyle)1;
				_tabActiveStyle.normal.textColor = Color.yellow;
				_toggleStyle = new GUIStyle(GUI.skin.toggle);
				_toggleStyle.fontSize = 12;
				_toggleStyle.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
				_toggleStyle.onNormal.textColor = Color.white;
				_labelStyle = new GUIStyle(GUI.skin.label);
				_labelStyle.fontSize = 11;
				_labelStyle.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
				_btnStyle = new GUIStyle(GUI.skin.button);
				_btnStyle.fontSize = 12;
				_btnStyle.fontStyle = (FontStyle)1;
			}
		}

		private Texture2D MakeSolidTexture(int width, int height, Color col)
		{
			//IL_000f: 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_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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			Color[] array = (Color[])(object)new Color[width * height];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = col;
			}
			Texture2D val = new Texture2D(width, height);
			val.SetPixels(array);
			val.Apply();
			return val;
		}

		private void OnGUI()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (_isOpen)
			{
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
				InitStyles();
				_windowRect = GUI.Window(9928374, _windowRect, new WindowFunction(DrawWindowContents), "Gatherer - Resource Tracking Menu", _winStyle);
				GUI.BringWindowToFront(9928374);
			}
		}

		private void DrawWindowContents(int windowId)
		{
			//IL_0131: 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_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			GathererConfig config = GathererManager.Instance.Config;
			if (config == null)
			{
				return;
			}
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Resources & Categories", (_activeTab == 0) ? _tabActiveStyle : _tabStyle, Array.Empty<GUILayoutOption>()))
			{
				_activeTab = 0;
			}
			if (GUILayout.Button("General & Pin Settings", (_activeTab == 1) ? _tabActiveStyle : _tabStyle, Array.Empty<GUILayoutOption>()))
			{
				_activeTab = 1;
			}
			if (GUILayout.Button("Custom Filters & Radar", (_activeTab == 2) ? _tabActiveStyle : _tabStyle, Array.Empty<GUILayoutOption>()))
			{
				_activeTab = 2;
			}
			if (GUILayout.Button("Close (Esc)", _btnStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
			{
				_isOpen = false;
				TakeInputFocus(focus: false);
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Map Icons & Visibility", (_activeTab == 3) ? _tabActiveStyle : _tabStyle, Array.Empty<GUILayoutOption>()))
			{
				_activeTab = 3;
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(8f);
			_scrollPos = GUILayout.BeginScrollView(_scrollPos, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			if (_activeTab == 0)
			{
				DrawResourcesTab(config);
			}
			else if (_activeTab == 1)
			{
				DrawGeneralSettingsTab(config);
			}
			else if (_activeTab == 2)
			{
				DrawFiltersTab(config);
			}
			else
			{
				DrawMapDisplayTab(config);
			}
			GUILayout.EndScrollView();
			GUILayout.Space(6f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Press " + ((object)config.ToggleUiKey.Value/*cast due to .constrained prefix*/).ToString() + " or Esc to toggle this menu anytime in-game.", _labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (_activeTab != 3)
			{
				if (GUILayout.Button("Select All", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
				{
					SetAllResources(config, val: true);
				}
				if (GUILayout.Button("Deselect All", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
				{
					SetAllResources(config, val: false);
				}
			}
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 24f));
		}

		private void DrawResourcesTab(GathererConfig config)
		{
			GUILayout.Label("Categories & Specific Resource Toggles", _headerStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Select the resources you want to track below. All resources are disabled by default until selected.", _labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			DrawCategoryHeader("Mushrooms", config.TrackMushrooms, delegate(bool val)
			{
				config.MarkRedMushroom.Value = val;
				config.MarkYellowMushroom.Value = val;
				config.MarkBlueMushroom.Value = val;
				config.MarkMagecap.Value = val;
				config.MarkJotunPuffs.Value = val;
				config.MarkSmokePuff.Value = val;
			});
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawToggle(config.MarkRedMushroom, "Red Mushroom", config.TrackMushrooms);
			DrawToggle(config.MarkYellowMushroom, "Yellow Mushroom", config.TrackMushrooms);
			DrawToggle(config.MarkBlueMushroom, "Blue Mushroom", config.TrackMushrooms);
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawToggle(config.MarkMagecap, "Magecap (Mistlands)", config.TrackMushrooms);
			DrawToggle(config.MarkJotunPuffs, "Jotun Puffs (Mistlands)", config.TrackMushrooms);
			DrawToggle(config.MarkSmokePuff, "Smoke Puff (Ashlands)", config.TrackMushrooms);
			GUILayout.EndHorizontal();
			GUILayout.Space(6f);
			DrawCategoryHeader("Berries", config.TrackBerries, delegate(bool val)
			{
				config.MarkRaspberry.Value = val;
				config.MarkBlueberry.Value = val;
				config.MarkCloudberry.Value = val;
			});
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawToggle(config.MarkRaspberry, "Raspberries", config.TrackBerries);
			DrawToggle(config.MarkBlueberry, "Blueberries", config.TrackBerries);
			DrawToggle(config.MarkCloudberry, "Cloudberries", config.TrackBerries);
			GUILayout.EndHorizontal();
			GUILayout.Space(6f);
			DrawCategoryHeader("Herbs & Wild Plants", config.TrackHerbsAndPlants, delegate(bool val)
			{
				config.MarkThistle.Value = val;
				config.MarkDandelion.Value = val;
				config.MarkCarrotSeeds.Value = val;
				config.MarkTurnipSeeds.Value = val;
				config.MarkOnionSeeds.Value = val;
				config.MarkFiddlehead.Value = val;
			});
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawToggle(config.MarkThistle, "Thistle", config.TrackHerbsAndPlants);
			DrawToggle(config.MarkDandelion, "Dandelion", config.TrackHerbsAndPlants);
			DrawToggle(config.MarkCarrotSeeds, "Carrot Seeds", config.TrackHerbsAndPlants);
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawToggle(config.MarkTurnipSeeds, "Turnip Seeds", config.TrackHerbsAndPlants);
			DrawToggle(config.MarkOnionSeeds, "Onion Seeds", config.TrackHerbsAndPlants);
			DrawToggle(config.MarkFiddlehead, "Fiddlehead (Ashlands)", config.TrackHerbsAndPlants);
			GUILayout.EndHorizontal();
			GUILayout.Space(6f);
			DrawCategoryHeader("Farming Crops (Wild)", config.TrackFarmingCrops, delegate(bool val)
			{
				config.MarkBarley.Value = val;
				config.MarkFlax.Value = val;
			});
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawToggle(config.MarkBarley, "Barley", config.TrackFarmingCrops);
			DrawToggle(config.MarkFlax, "Flax", config.TrackFarmingCrops);
			GUILayout.EndHorizontal();
			GUILayout.Space(6f);
			DrawCategoryHeader("Ores & Mineral Veins", config.TrackOresAndVeins, delegate(bool val)
			{
				config.MarkCopper.Value = val;
				config.MarkTin.Value = val;
				config.MarkSilver.Value = val;
				config.MarkIronMudpile.Value = val;
				config.MarkObsidian.Value = val;
				config.MarkFlametal.Value = val;
			});
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawToggle(config.MarkCopper, "Copper Deposit", config.TrackOresAndVeins);
			DrawToggle(config.MarkTin, "Tin Deposit", config.TrackOresAndVeins);
			DrawToggle(config.MarkSilver, "Silver Vein", config.TrackOresAndVeins);
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawToggle(config.MarkIronMudpile, "Muddy Scrap Pile (Iron)", config.TrackOresAndVeins);
			DrawToggle(config.MarkObsidian, "Obsidian", config.TrackOresAndVeins);
			DrawToggle(config.MarkFlametal, "Flametal (Ashlands)", config.TrackOresAndVeins);
			GUILayout.EndHorizontal();
			GUILayout.Space(6f);
			DrawCategoryHeader("Special POIs & Beehives", config.TrackSpecial, delegate(bool val)
			{
				config.MarkBeehive.Value = val;
				config.MarkVegvisir.Value = val;
				config.MarkSurtlingSpawner.Value = val;
				config.MarkAncientRoot.Value = val;
			});
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawToggle(config.MarkBeehive, "Wild Beehives", config.TrackSpecial);
			DrawToggle(config.MarkVegvisir, "Vegvisir Runestones", config.TrackSpecial);
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawToggle(config.MarkSurtlingSpawner, "Surtling Spawners", config.TrackSpecial);
			DrawToggle(config.MarkAncientRoot, "Ancient Roots (Sap)", config.TrackSpecial);
			GUILayout.EndHorizontal();
		}

		private void DrawMapDisplayTab(GathererConfig config)
		{
			GUILayout.Label("Map Icons & Visibility", _headerStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Hide/show existing resource pins without changing tracking or sharing.", _labelStyle, Array.Empty<GUILayoutOption>());
			DrawToggle(config.UseResourceIcons, "Use item icons");
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Show All", Array.Empty<GUILayoutOption>()))
			{
				foreach (ConfigEntry<bool> value in config.ResourceVisibility.Values)
				{
					value.Value = true;
				}
			}
			if (GUILayout.Button("Hide All", Array.Empty<GUILayoutOption>()))
			{
				foreach (ConfigEntry<bool> value2 in config.ResourceVisibility.Values)
				{
					value2.Value = false;
				}
			}
			GUILayout.EndHorizontal();
			foreach (ResourceDefinition allDefinition in ResourceRegistry.AllDefinitions)
			{
				DrawToggle(config.ResourceVisibility[allDefinition.Id], allDefinition.DisplayName);
			}
			GUILayout.Label("Filters apply to world map and minimap. Other players keep their own visibility choices.", _labelStyle, Array.Empty<GUILayoutOption>());
		}

		private void DrawGeneralSettingsTab(GathererConfig config)
		{
			GUILayout.Label("General & Cartography Table Settings", _headerStyle, Array.Empty<GUILayoutOption>());
			config.Enabled.Value = GUILayout.Toggle(config.Enabled.Value, " Mod Enabled (Master Toggle)", _toggleStyle, Array.Empty<GUILayoutOption>());
			config.ShareOnCartographyTable.Value = GUILayout.Toggle(config.ShareOnCartographyTable.Value, " Share On Cartography Table (Synchronize pins with other players via Cartography Table)", _toggleStyle, Array.Empty<GUILayoutOption>());
			config.ShowHudNotification.Value = GUILayout.Toggle(config.ShowHudNotification.Value, " Show HUD Notifications (Top-left on-screen message when a node is marked)", _toggleStyle, Array.Empty<GUILayoutOption>());
			config.CleanPinNames.Value = GUILayout.Toggle(config.CleanPinNames.Value, " Clean Pin Names (e.g. 'Copper' instead of 'Copper deposit')", _toggleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			GUILayout.Label("Discovery Mode", _sectionStyle, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Toggle(config.Mode.Value == DiscoveryMode.InteractAndProximity, " Interact & Proximity Radar (Default)", _toggleStyle, Array.Empty<GUILayoutOption>()))
			{
				config.Mode.Value = DiscoveryMode.InteractAndProximity;
			}
			if (GUILayout.Toggle(config.Mode.Value == DiscoveryMode.InteractOnly, " Interact Only (Classic WoW)", _toggleStyle, Array.Empty<GUILayoutOption>()))
			{
				config.Mode.Value = DiscoveryMode.InteractOnly;
			}
			if (GUILayout.Toggle(config.Mode.Value == DiscoveryMode.InteractAndHover, " Interact & Hover", _toggleStyle, Array.Empty<GUILayoutOption>()))
			{
				config.Mode.Value = DiscoveryMode.InteractAndHover;
			}
			if (GUILayout.Toggle(config.Mode.Value == DiscoveryMode.All, " All Triggers", _toggleStyle, Array.Empty<GUILayoutOption>()))
			{
				config.Mode.Value = DiscoveryMode.All;
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(10f);
			GUILayout.Label("Pin Label Prefix", _sectionStyle, Array.Empty<GUILayoutOption>());
			config.PinNamePrefix.Value = GUILayout.TextField(config.PinNamePrefix.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
			GUILayout.Label("Optional prefix added before names on the map (e.g. '[G] ' or empty).", _labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			GUILayout.Label("Duplicate Merging Distances (Radius in Meters)", _sectionStyle, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label($"Herb/Mushroom Radius: {config.HerbMergeRadius.Value:F0}m", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(170f) });
			config.HerbMergeRadius.Value = GUILayout.HorizontalSlider(config.HerbMergeRadius.Value, 2f, 30f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label($"Ore Deposit Radius: {config.OreMergeRadius.Value:F0}m", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(170f) });
			config.OreMergeRadius.Value = GUILayout.HorizontalSlider(config.OreMergeRadius.Value, 5f, 50f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
			GUILayout.EndHorizontal();
		}

		private void DrawFiltersTab(GathererConfig config)
		{
			GUILayout.Label("Advanced Filters & Radar Tuning", _headerStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Proximity Radar Sweep Radius", _sectionStyle, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label($"{config.ProximityRadius.Value:F0} meters", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) });
			config.ProximityRadius.Value = GUILayout.HorizontalSlider(config.ProximityRadius.Value, 5f, 40f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
			GUILayout.EndHorizontal();
			GUILayout.Space(10f);
			GUILayout.Label("Custom Exclude Filter (Blacklist)", _sectionStyle, Array.Empty<GUILayoutOption>());
			config.CustomExcludeFilter.Value = GUILayout.TextField(config.CustomExcludeFilter.Value, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Comma-separated prefab or display names to NEVER mark (e.g. 'Copper, Flint, Stone').", _labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			GUILayout.Label("Custom Include Filter (Whitelist / Modded items)", _sectionStyle, Array.Empty<GUILayoutOption>());
			config.CustomIncludeFilter.Value = GUILayout.TextField(config.CustomIncludeFilter.Value, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Comma-separated prefab names to ALWAYS mark even from other mods (e.g. 'DragonEgg, GoblinTotem').", _labelStyle, Array.Empty<GUILayoutOption>());
		}

		private void DrawCategoryHeader(string title, ConfigEntry<bool> entry, Action<bool>? onToggleAll = null)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(title, _sectionStyle, Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			bool flag = GUILayout.Toggle(entry.Value, entry.Value ? "Category: ON " : "Category: OFF", _toggleStyle, Array.Empty<GUILayoutOption>());
			if (flag != entry.Value)
			{
				entry.Value = flag;
				onToggleAll?.Invoke(flag);
			}
			GUILayout.EndHorizontal();
		}

		private void DrawToggle(ConfigEntry<bool> entry, string label, ConfigEntry<bool>? parentCategory = null)
		{
			bool value = entry.Value;
			bool flag = GUILayout.Toggle(value, " " + label, _toggleStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(210f) });
			if (flag != value)
			{
				entry.Value = flag;
				if (flag && parentCategory != null && !parentCategory.Value)
				{
					parentCategory.Value = true;
				}
			}
		}

		private void SetAllResources(GathererConfig config, bool val)
		{
			config.TrackMushrooms.Value = val;
			config.TrackBerries.Value = val;
			config.TrackHerbsAndPlants.Value = val;
			config.TrackFarmingCrops.Value = val;
			config.TrackOresAndVeins.Value = val;
			config.TrackBeehives.Value = val;
			config.TrackSpecial.Value = val;
			config.MarkRedMushroom.Value = val;
			config.MarkYellowMushroom.Value = val;
			config.MarkBlueMushroom.Value = val;
			config.MarkMagecap.Value = val;
			config.MarkJotunPuffs.Value = val;
			config.MarkSmokePuff.Value = val;
			config.MarkRaspberry.Value = val;
			config.MarkBlueberry.Value = val;
			config.MarkCloudberry.Value = val;
			config.MarkThistle.Value = val;
			config.MarkDandelion.Value = val;
			config.MarkCarrotSeeds.Value = val;
			config.MarkTurnipSeeds.Value = val;
			config.MarkOnionSeeds.Value = val;
			config.MarkFiddlehead.Value = val;
			config.MarkBarley.Value = val;
			config.MarkFlax.Value = val;
			config.MarkCopper.Value = val;
			config.MarkTin.Value = val;
			config.MarkSilver.Value = val;
			config.MarkIronMudpile.Value = val;
			config.MarkObsidian.Value = val;
			config.MarkFlametal.Value = val;
			config.MarkBeehive.Value = val;
			config.MarkVegvisir.Value = val;
			config.MarkSurtlingSpawner.Value = val;
			config.MarkAncientRoot.Value = val;
		}

		private void OnDestroy()
		{
			if ((Object)(object)_bgTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_bgTexture);
			}
			if ((Object)(object)_tabActiveTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_tabActiveTexture);
			}
		}
	}
	public static class GathererNotifications
	{
		public static void ShowMarked(string resourceName)
		{
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				string text = "[Gatherer] Marked " + resourceName;
				((Character)Player.m_localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
			}
		}
	}
	public static class ResourcePinPresentation
	{
		private readonly struct VisualState
		{
			public readonly GameObject Marker;

			public readonly GameObject? Label;

			public readonly bool MarkerActive;

			public readonly bool LabelActive;

			public readonly Image Image;

			public readonly Sprite Sprite;

			public VisualState(PinData pin)
			{
				Marker = ((Component)pin.m_uiElement).gameObject;
				PinNameData namePinData = pin.m_NamePinData;
				Label = ((namePinData != null) ? namePinData.PinNameGameObject : null);
				MarkerActive = Marker.activeSelf;
				LabelActive = (Object)(object)Label != (Object)null && Label.activeSelf;
				Image = pin.m_iconElement;
				Sprite = Image.sprite;
			}

			public void Restore()
			{
				if ((Object)(object)Marker != (Object)null)
				{
					Marker.SetActive(MarkerActive);
				}
				if ((Object)(object)Label != (Object)null)
				{
					Label.SetActive(LabelActive);
				}
				if ((Object)(object)Image != (Object)null)
				{
					Image.sprite = Sprite;
				}
			}
		}

		private static readonly Dictionary<string, string> ItemNames = new Dictionary<string, string>
		{
			["Mushroom"] = "Mushroom",
			["MushroomYellow"] = "MushroomYellow",
			["MushroomBlue"] = "MushroomBlue",
			["Magecap"] = "MushroomMagecap",
			["JotunPuffs"] = "MushroomJotunPuffs",
			["SmokePuff"] = "MushroomSmokePuff",
			["Raspberry"] = "Raspberry",
			["Blueberry"] = "Blueberries",
			["Cloudberry"] = "Cloudberry",
			["Thistle"] = "Thistle",
			["Dandelion"] = "Dandelion",
			["CarrotSeeds"] = "CarrotSeeds",
			["TurnipSeeds"] = "TurnipSeeds",
			["OnionSeeds"] = "OnionSeeds",
			["Fiddlehead"] = "Fiddleheadfern",
			["Barley"] = "Barley",
			["Flax"] = "Flax",
			["Copper"] = "CopperOre",
			["Tin"] = "TinOre",
			["Silver"] = "SilverOre",
			["IronMudpile"] = "IronScrap",
			["Obsidian"] = "Obsidian",
			["Flametal"] = "FlametalOreNew",
			["Beehive"] = "QueenBee"
		};

		private static readonly FieldRef<Minimap, List<PinData>> Pins = AccessTools.FieldRefAccess<Minimap, List<PinData>>("m_pins");

		private static readonly Dictionary<string, ResourceDefinition?> Matches = new Dictionary<string, ResourceDefinition>();

		private static readonly Dictionary<string, Sprite?> Icons = new Dictionary<string, Sprite>();

		private static readonly List<VisualState> Changed = new List<VisualState>();

		private static ObjectDB? _database;

		private static string _prefix = "";

		public static void Restore()
		{
			foreach (VisualState item in Changed)
			{
				item.Restore();
			}
			Changed.Clear();
		}

		public static void Reset()
		{
			Restore();
			Matches.Clear();
			Icons.Clear();
			_database = null;
			_prefix = "";
		}

		public static void Apply(Minimap map)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Invalid comparison between Unknown and I4
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Invalid comparison between Unknown and I4
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Invalid comparison between Unknown and I4
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Invalid comparison between Unknown and I4
			GathererConfig config = GathererManager.Instance.Config;
			if (config == null || !config.Enabled.Value)
			{
				return;
			}
			if (_prefix != config.PinNamePrefix.Value)
			{
				_prefix = config.PinNamePrefix.Value;
				Matches.Clear();
			}
			if ((Object)(object)_database != (Object)(object)ObjectDB.instance)
			{
				_database = ObjectDB.instance;
				Icons.Clear();
			}
			foreach (PinData item in Pins.Invoke(map))
			{
				if (((int)item.m_type != 0 && (int)item.m_type != 1 && (int)item.m_type != 2 && (int)item.m_type != 3 && (int)item.m_type != 6) || (Object)(object)item.m_uiElement == (Object)null || (Object)(object)item.m_iconElement == (Object)null)
				{
					continue;
				}
				if (!Matches.TryGetValue(item.m_name, out ResourceDefinition value))
				{
					value = ResourcePinMatcher.Match(item.m_name, (string key) => (Localization.instance == null) ? key : Localization.instance.Localize(key), _prefix);
					if (Matches.Count >= 4096)
					{
						Matches.Clear();
					}
					Matches[item.m_name] = value;
				}
				if (value == null)
				{
					continue;
				}
				ConfigEntry<bool> value2;
				bool flag = !config.ResourceVisibility.TryGetValue(value.Id, out value2) || value2.Value;
				Sprite val = (config.UseResourceIcons.Value ? GetIcon(value) : null);
				if (flag && (Object)(object)val == (Object)null)
				{
					continue;
				}
				Changed.Add(new VisualState(item));
				if (!flag)
				{
					((Component)item.m_uiElement).gameObject.SetActive(false);
					PinNameData namePinData = item.m_NamePinData;
					if ((Object)(object)((namePinData != null) ? namePinData.PinNameGameObject : null) != (Object)null)
					{
						item.m_NamePinData.PinNameGameObject.SetActive(false);
					}
				}
				else
				{
					item.m_iconElement.sprite = val;
				}
			}
		}

		private static Sprite? GetIcon(ResourceDefinition resource)
		{
			if ((Object)(object)_database == (Object)null)
			{
				return null;
			}
			if (Icons.TryGetValue(resource.Id, out Sprite value))
			{
				return value;
			}
			if (ItemNames.TryGetValue(resource.Id, out string value2))
			{
				GameObject itemPrefab = _database.GetItemPrefab(value2);
				ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val != (Object)null && val.m_itemData.m_shared.m_icons.Length != 0)
				{
					value = val.m_itemData.GetIcon();
				}
			}
			Icons[resource.Id] = value;
			return value;
		}
	}
}
namespace ValheimGatherer.Patches
{
	[HarmonyPatch(typeof(Destructible), "Damage")]
	public static class DestructiblePatch
	{
		[HarmonyPrefix]
		public static void Prefix(Destructible __instance, HitData hit)
		{
			if (!((Object)(object)__instance == (Object)null) && hit != null && (Object)(object)hit.GetAttacker() == (Object)(object)Player.m_localPlayer)
			{
				GathererManager.Instance.TryProcessGameObject(((Component)__instance).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateHover")]
	public static class HoverPatch
	{
		private static float _lastHoverProcessTime;

		[HarmonyPostfix]
		public static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			GathererConfig config = GathererManager.Instance.Config;
			if (config == null || !config.Enabled.Value)
			{
				return;
			}
			DiscoveryMode value = config.Mode.Value;
			if ((value == DiscoveryMode.InteractAndHover || value == DiscoveryMode.All) && !(Time.time - _lastHoverProcessTime < 0.5f))
			{
				GameObject hoverObject = ((Humanoid)__instance).GetHoverObject();
				if ((Object)(object)hoverObject != (Object)null)
				{
					_lastHoverProcessTime = Time.time;
					GathererManager.Instance.TryProcessGameObject(hoverObject);
				}
			}
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
	public static class GameCameraMouseCapturePatch
	{
		[HarmonyPrefix]
		public static bool Prefix()
		{
			if (GathererInGameUI.IsMenuOpen)
			{
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(PlayerController), "TakeInput", new Type[] { typeof(bool) })]
	public static class PlayerControllerTakeInputPatch
	{
		[HarmonyPrefix]
		public static bool Prefix(ref bool __result)
		{
			if (GathererInGameUI.IsMenuOpen)
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Player), "TakeInput")]
	public static class PlayerTakeInputPatch
	{
		[HarmonyPrefix]
		public static bool Prefix(ref bool __result)
		{
			if (GathererInGameUI.IsMenuOpen)
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(MapTable), "OnWrite")]
	public static class MapTableOnWritePatch
	{
		[HarmonyPostfix]
		public static void Postfix(MapTable __instance, Switch caller, Humanoid user, ItemData item)
		{
			if (!((Object)(object)user != (Object)(object)Player.m_localPlayer))
			{
				GathererConfig config = GathererManager.Instance.Config;
				if (config != null && config.ShareOnCartographyTable.Value && config.ShowHudNotification.Value)
				{
					((Character)Player.m_localPlayer).Message((MessageType)1, "[Gatherer] Map discoveries and resource pins recorded to Cartography Table!", 0, (Sprite)null, false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(MapTable), "OnRead", new Type[]
	{
		typeof(Switch),
		typeof(Humanoid),
		typeof(ItemData),
		typeof(bool)
	})]
	public static class MapTableOnReadPatch
	{
		[HarmonyPostfix]
		public static void Postfix(MapTable __instance, Switch caller, Humanoid user, ItemData item, bool showMessage)
		{
			if (!((Object)(object)user != (Object)(object)Player.m_localPlayer) && showMessage)
			{
				GathererConfig config = GathererManager.Instance.Config;
				if (config != null && config.ShareOnCartographyTable.Value && config.ShowHudNotification.Value)
				{
					((Character)Player.m_localPlayer).Message((MessageType)1, "[Gatherer] Synchronized map discoveries and resource pins from Cartography Table!", 0, (Sprite)null, false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(MineRock), "Damage")]
	public static class MineRockPatch
	{
		[HarmonyPrefix]
		public static void Prefix(MineRock __instance, HitData hit)
		{
			if (!((Object)(object)__instance == (Object)null) && hit != null && (Object)(object)hit.GetAttacker() == (Object)(object)Player.m_localPlayer)
			{
				GathererManager.Instance.TryProcessGameObject(((Component)__instance).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(MineRock5), "Damage")]
	public static class MineRock5Patch
	{
		[HarmonyPrefix]
		public static void Prefix(MineRock5 __instance, HitData hit)
		{
			if (!((Object)(object)__instance == (Object)null) && hit != null && (Object)(object)hit.GetAttacker() == (Object)(object)Player.m_localPlayer)
			{
				GathererManager.Instance.TryProcessGameObject(((Component)__instance).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "UpdatePins")]
	public static class MinimapPresentationPatch
	{
		[HarmonyPrefix]
		public static void Prefix()
		{
			ResourcePinPresentation.Restore();
		}

		[HarmonyPostfix]
		public static void Postfix(Minimap __instance)
		{
			ResourcePinPresentation.Apply(__instance);
		}
	}
	[HarmonyPatch(typeof(Minimap), "OnDestroy")]
	public static class MinimapPresentationCleanupPatch
	{
		[HarmonyPrefix]
		public static void Prefix()
		{
			ResourcePinPresentation.Reset();
		}
	}
	[HarmonyPatch(typeof(Localization), "SetupLanguage")]
	public static class ResourcePinLanguagePatch
	{
		[HarmonyPostfix]
		public static void Postfix()
		{
			ResourcePinPresentation.Reset();
		}
	}
	[HarmonyPatch(typeof(Pickable), "Interact")]
	public static class PickablePatch
	{
		[HarmonyPrefix]
		public static void Prefix(Pickable __instance, Humanoid character)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)character == (Object)null) && !((Object)(object)character != (Object)(object)Player.m_localPlayer))
			{
				GathererManager.Instance.TryProcessGameObject(((Component)__instance).gameObject);
			}
		}
	}
}
namespace ValheimGatherer.Core
{
	public struct PinCheckData
	{
		public Vector3 Position;

		public string Name;

		public PinCheckData(Vector3 position, string name)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Position = position;
			Name = name;
		}
	}
	public class GathererManager
	{
		private static GathererManager? _instance;

		private static readonly FieldRef<Minimap, List<PinData>> PinsFieldRef = AccessTools.FieldRefAccess<Minimap, List<PinData>>("m_pins");

		private ManualLogSource? _logger;

		public static GathererManager Instance => _instance ?? (_instance = new GathererManager());

		public GathererConfig? Config { get; private set; }

		public void Initialize(GathererConfig config, ManualLogSource logger)
		{
			Config = config;
			_logger = logger;
		}

		public bool TryProcessGameObject(GameObject? go, Vector3? explicitPos = null)
		{
			//IL_02a2: 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_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03af: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			//IL_0420: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)go == (Object)null || Config == null || !Config.Enabled.Value)
			{
				return false;
			}
			if ((Object)(object)Minimap.instance == (Object)null)
			{
				return false;
			}
			Piece val = go.GetComponentInParent<Piece>() ?? go.GetComponent<Piece>();
			if ((Object)(object)val != (Object)null && val.IsPlacedByPlayer())
			{
				return false;
			}
			string name = ((Object)go).name;
			string text = (name.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase) ? name.Substring(0, name.Length - 7) : name);
			string text2 = "";
			string text3 = "";
			Pickable val2 = go.GetComponentInParent<Pickable>() ?? go.GetComponent<Pickable>();
			if ((Object)(object)val2 != (Object)null)
			{
				if ((Object)(object)val2.m_itemPrefab != (Object)null)
				{
					text3 = ((Object)val2.m_itemPrefab).name;
				}
				text2 = val2.GetHoverName();
			}
			if (string.IsNullOrEmpty(text2))
			{
				MineRock val3 = go.GetComponentInParent<MineRock>() ?? go.GetComponent<MineRock>();
				if ((Object)(object)val3 != (Object)null)
				{
					text2 = val3.m_name;
				}
			}
			if (string.IsNullOrEmpty(text2))
			{
				MineRock5 val4 = go.GetComponentInParent<MineRock5>() ?? go.GetComponent<MineRock5>();
				if ((Object)(object)val4 != (Object)null)
				{
					text2 = val4.m_name;
				}
			}
			if (string.IsNullOrEmpty(text2))
			{
				Beehive val5 = go.GetComponentInParent<Beehive>() ?? go.GetComponent<Beehive>();
				if ((Object)(object)val5 != (Object)null)
				{
					text2 = val5.m_name;
				}
			}
			if (string.IsNullOrEmpty(text2))
			{
				Hoverable val6 = go.GetComponentInParent<Hoverable>() ?? go.GetComponent<Hoverable>();
				if (val6 != null)
				{
					text2 = val6.GetHoverText();
				}
			}
			string text4 = text2;
			if (!string.IsNullOrEmpty(text2) && Localization.instance != null)
			{
				text4 = Localization.instance.Localize(text2);
			}
			ResourceDefinition resourceDefinition = null;
			if (!string.IsNullOrEmpty(text3))
			{
				resourceDefinition = ResourceRegistry.Match(text3, text2, text4);
			}
			if (resourceDefinition == null)
			{
				resourceDefinition = ResourceRegistry.Match(text, text2, text4);
			}
			if (resourceDefinition == null)
			{
				if (!Config.IsCustomIncluded(text) && (string.IsNullOrEmpty(text3) || !Config.IsCustomIncluded(text3)) && (string.IsNullOrEmpty(text4) || !Config.IsCustomIncluded(text4)))
				{
					return false;
				}
				string text5 = ((!string.IsNullOrEmpty(text4)) ? text4 : text);
				resourceDefinition = new ResourceDefinition(text, text5, text5, ResourceCategory.Custom, Config.DefaultPinIcon.Value, new string[1] { text }, new string[0], Config.HerbMergeRadius.Value, (GathererConfig cfg) => true);
			}
			if (!ResourceRegistry.IsEnabled(resourceDefinition, Config, text, text4))
			{
				return false;
			}
			Vector3 val7 = (Vector3)(((??)explicitPos) ?? go.transform.position);
			float value;
			PinIconType value2;
			if (resourceDefinition.Category == ResourceCategory.OresAndVeins)
			{
				value = Config.OreMergeRadius.Value;
				value2 = Config.OrePinIcon.Value;
			}
			else if (resourceDefinition.Category == ResourceCategory.Special || resourceDefinition.Category == ResourceCategory.Beehives)
			{
				value = Config.SpecialMergeRadius.Value;
				value2 = Config.SpecialPinIcon.Value;
			}
			else
			{
				value = Config.HerbMergeRadius.Value;
				value2 = Config.DefaultPinIcon.Value;
			}
			string text6 = (Config.CleanPinNames.Value ? resourceDefinition.CleanShortName : resourceDefinition.DisplayName);
			if (!string.IsNullOrEmpty(text4) && !Config.CleanPinNames.Value)
			{
				text6 = text4;
			}
			string text7 = (string.IsNullOrEmpty(Config.PinNamePrefix.Value) ? text6 : (Config.PinNamePrefix.Value + text6));
			if (IsDuplicateExistingPin(val7, text6, value))
			{
				return false;
			}
			bool value3 = Config.ShareOnCartographyTable.Value;
			long num = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerID() : 0);
			PlatformUserID none = PlatformUserID.None;
			if (Minimap.instance.AddPin(val7, (PinType)value2, text7, value3, false, num, none) != null)
			{
				ManualLogSource? logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)$"[Gatherer] Added pin '{text7}' at {val7} (shared via Cartography: {value3})");
				}
				if (Config.ShowHudNotification.Value)
				{
					GathererNotifications.ShowMarked(text6);
				}
				return true;
			}
			return false;
		}

		public bool IsDuplicateExistingPin(Vector3 pos, string resourceName, float radius)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Minimap.instance == (Object)null)
			{
				return false;
			}
			List<PinData> list = PinsFieldRef.Invoke(Minimap.instance);
			if (list == null)
			{
				return false;
			}
			float num = radius * radius;
			for (int i = 0; i < list.Count; i++)
			{
				PinData val = list[i];
				if (val != null)
				{
					float num2 = pos.x - val.m_pos.x;
					float num3 = pos.z - val.m_pos.z;
					if (num2 * num2 + num3 * num3 <= num && (string.Equals(val.m_name, resourceName, StringComparison.OrdinalIgnoreCase) || (!string.IsNullOrEmpty(val.m_name) && val.m_name.IndexOf(resourceName, StringComparison.OrdinalIgnoreCase) >= 0) || (!string.IsNullOrEmpty(resourceName) && resourceName.IndexOf(val.m_name, StringComparison.OrdinalIgnoreCase) >= 0)))
					{
						return true;
					}
				}
			}
			return false;
		}

		public static bool CheckDuplicate(Vector3 pos, string resourceName, IEnumerable<PinCheckData> existingPins, float radius)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			float num = radius * radius;
			foreach (PinCheckData existingPin in existingPins)
			{
				float num2 = pos.x - existingPin.Position.x;
				float num3 = pos.z - existingPin.Position.z;
				if (num2 * num2 + num3 * num3 <= num && (string.Equals(existingPin.Name, resourceName, StringComparison.OrdinalIgnoreCase) || (!string.IsNullOrEmpty(existingPin.Name) && existingPin.Name.IndexOf(resourceName, StringComparison.OrdinalIgnoreCase) >= 0) || (!string.IsNullOrEmpty(resourceName) && resourceName.IndexOf(existingPin.Name, StringComparison.OrdinalIgnoreCase) >= 0)))
				{
					return true;
				}
			}
			return false;
		}
	}
	public class ProximityScanner : MonoBehaviour
	{
		private readonly Collider[] _hitBuffer = (Collider[])(object)new Collider[128];

		private readonly HashSet<int> _scannedObjectIds = new HashSet<int>();

		private void Start()
		{
			((MonoBehaviour)this).StartCoroutine(ScanRoutine());
		}

		private IEnumerator ScanRoutine()
		{
			while (true)
			{
				GathererConfig config = GathererManager.Instance.Config;
				if (config == null || !config.Enabled.Value)
				{
					yield return (object)new WaitForSeconds(3f);
					continue;
				}
				DiscoveryMode value = config.Mode.Value;
				if (value != DiscoveryMode.InteractAndProximity && value != DiscoveryMode.All)
				{
					yield return (object)new WaitForSeconds(3f);
					continue;
				}
				if ((Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).IsDead() || (Object)(object)Minimap.instance == (Object)null)
				{
					yield return (object)new WaitForSeconds(2f);
					continue;
				}
				PerformScan(config.ProximityRadius.Value);
				float num = Mathf.Max(1f, config.ProximityScanInterval.Value);
				yield return (object)new WaitForSeconds(num);
			}
		}

		private void PerformScan(float radius)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.OverlapSphereNonAlloc(((Component)Player.m_localPlayer).transform.position, radius, _hitBuffer);
			_scannedObjectIds.Clear();
			for (int i = 0; i < num; i++)
			{
				Collider val = _hitBuffer[i];
				if (!((Object)(object)val == (Object)null))
				{
					GameObject gameObject = ((Component)val).gameObject;
					int instanceID = ((Object)gameObject).GetInstanceID();
					if (!_scannedObjectIds.Contains(instanceID))
					{
						_scannedObjectIds.Add(instanceID);
						GathererManager.Instance.TryProcessGameObject(gameObject);
					}
				}
			}
		}
	}
	public class ResourceDefinition
	{
		public string Id { get; }

		public string DisplayName { get; }

		public string CleanShortName { get; }

		public ResourceCategory Category { get; }

		public PinIconType DefaultIcon { get; }

		public string[] PrefabNames { get; }

		public string[] LocalizationKeys { get; }

		public float DefaultMergeRadius { get; }

		public Func<GathererConfig, bool> IsEnabledFunc { get; }

		public ResourceDefinition(string id, string displayName, string cleanShortName, ResourceCategory category, PinIconType defaultIcon, string[] prefabNames, string[] localizationKeys, float defaultMergeRadius, Func<GathererConfig, bool> isEnabledFunc)
		{
			Id = id;
			DisplayName = displayName;
			CleanShortName = cleanShortName;
			Category = category;
			DefaultIcon = defaultIcon;
			PrefabNames = prefabNames;
			LocalizationKeys = localizationKeys;
			DefaultMergeRadius = defaultMergeRadius;
			IsEnabledFunc = isEnabledFunc;
		}

		public bool Matches(string prefabName, string hoverName, string localizedName)
		{
			if (!string.IsNullOrEmpty(hoverName))
			{
				string[] localizationKeys = LocalizationKeys;
				foreach (string b in localizationKeys)
				{
					if (string.Equals(hoverName, b, StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
				}
			}
			if (!string.IsNullOrEmpty(prefabName))
			{
				string[] localizationKeys = PrefabNames;
				foreach (string b2 in localizationKeys)
				{
					if (string.Equals(prefabName, b2, StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
				}
			}
			if (!string.IsNullOrEmpty(localizedName) && (string.Equals(localizedName, DisplayName, StringComparison.OrdinalIgnoreCase) || string.Equals(localizedName, CleanShortName, StringComparison.OrdinalIgnoreCase)))
			{
				return true;
			}
			if (!string.IsNullOrEmpty(prefabName))
			{
				string[] localizationKeys = PrefabNames;
				foreach (string text in localizationKeys)
				{
					if (prefabName.StartsWith(text + "_", StringComparison.OrdinalIgnoreCase) || prefabName.StartsWith(text + "(", StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	public static class ResourcePinMatcher
	{
		public static ResourceDefinition? Match(string? name, Func<string, string>? localize = null, string prefix = "")
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return null;
			}
			if (!string.IsNullOrEmpty(prefix) && name.StartsWith(prefix, StringComparison.Ordinal))
			{
				name = name.Substring(prefix.Length);
			}
			ResourceDefinition result = null;
			int longestMatch = 0;
			foreach (ResourceDefinition allDefinition in ResourceRegistry.AllDefinitions)
			{
				Check(allDefinition, allDefinition.Id);
				Check(allDefinition, allDefinition.DisplayName);
				Check(allDefinition, allDefinition.CleanShortName);
				string[] localizationKeys = allDefinition.LocalizationKeys;
				foreach (string text in localizationKeys)
				{
					Check(allDefinition, text);
					if (localize != null)
					{
						Check(allDefinition, localize(text));
					}
				}
			}
			return result;
			void Check(ResourceDefinition resource, string candidate)
			{
				if (!string.IsNullOrEmpty(candidate) && candidate.Length > longestMatch && name.EndsWith(candidate, StringComparison.OrdinalIgnoreCase))
				{
					int num = name.Length - candidate.Length;
					if (num == 0 || char.IsWhiteSpace(name[num - 1]) || name[num - 1] == ']')
					{
						longestMatch = candidate.Length;
						result = resource;
					}
				}
			}
		}
	}
	public class ResourceRegistry
	{
		private static readonly List<ResourceDefinition> Definitions;

		public static IReadOnlyList<ResourceDefinition> AllDefinitions => Definitions;

		static ResourceRegistry()
		{
			Definitions = new List<ResourceDefinition>();
			RegisterDefaults();
		}

		private static void RegisterDefaults()
		{
			Register(new ResourceDefinition("MushroomYellow", "Yellow Mushroom", "Yellow Mushroom", ResourceCategory.Mushrooms, PinIconType.Dot, new string[2] { "Pickable_Mushroom_yellow", "MushroomYellow" }, new string[1] { "$item_mushroomyellow" }, 10f, (GathererConfig cfg) => cfg.TrackMushrooms.Value && cfg.MarkYellowMushroom.Value));
			Register(new ResourceDefinition("MushroomBlue", "Blue Mushroom", "Blue Mushroom", ResourceCategory.Mushrooms, PinIconType.Dot, new string[2] { "Pickable_Mushroom_blue", "MushroomBlue" }, new string[1] { "$item_mushroomblue" }, 10f, (GathererConfig cfg) => cfg.TrackMushrooms.Value && cfg.MarkBlueMushroom.Value));
			Register(new ResourceDefinition("Magecap", "Magecap", "Magecap", ResourceCategory.Mushrooms, PinIconType.Dot, new string[2] { "Pickable_Magecap", "Magecap" }, new string[1] { "$item_magecap" }, 10f, (GathererConfig cfg) => cfg.TrackMushrooms.Value && cfg.MarkMagecap.Value));
			Register(new ResourceDefinition("JotunPuffs", "Jotun Puffs", "Jotun Puffs", ResourceCategory.Mushrooms, PinIconType.Dot, new string[2] { "Pickable_JotunPuffs", "JotunPuffs" }, new string[1] { "$item_jotunpuffs" }, 10f, (GathererConfig cfg) => cfg.TrackMushrooms.Value && cfg.MarkJotunPuffs.Value));
			Register(new ResourceDefinition("SmokePuff", "Smoke Puff", "Smoke Puff", ResourceCategory.Mushrooms, PinIconType.Dot, new string[2] { "Pickable_SmokePuff", "SmokePuff" }, new string[1] { "$item_smokepuff" }, 10f, (GathererConfig cfg) => cfg.TrackMushrooms.Value && cfg.MarkSmokePuff.Value));
			Register(new ResourceDefinition("Mushroom", "Mushroom", "Mushroom", ResourceCategory.Mushrooms, PinIconType.Dot, new string[2] { "Pickable_Mushroom", "Mushroom" }, new string[1] { "$item_mushroom" }, 10f, (GathererConfig cfg) => cfg.TrackMushrooms.Value && cfg.MarkRedMushroom.Value));
			Register(new ResourceDefinition("Raspberry", "Raspberries", "Raspberries", ResourceCategory.Berries, PinIconType.Dot, new string[3] { "Pickable_Raspberry", "Raspberry", "Raspberries" }, new string[1] { "$item_raspberries" }, 10f, (GathererConfig cfg) => cfg.TrackBerries.Value && cfg.MarkRaspberry.Value));
			Register(new ResourceDefinition("Blueberry", "Blueberries", "Blueberries", ResourceCategory.Berries, PinIconType.Dot, new string[2] { "Pickable_Blueberries", "Blueberries" }, new string[1] { "$item_blueberries" }, 10f, (GathererConfig cfg) => cfg.TrackBerries.Value && cfg.MarkBlueberry.Value));
			Register(new ResourceDefinition("Cloudberry", "Cloudberries", "Cloudberries", ResourceCategory.Berries, PinIconType.Dot, new string[3] { "Pickable_Cloudberry", "Cloudberry", "Cloudberries" }, new string[1] { "$item_cloudberry" }, 10f, (GathererConfig cfg) => cfg.TrackBerries.Value && cfg.MarkCloudberry.Value));
			Register(new ResourceDefinition("Thistle", "Thistle", "Thistle", ResourceCategory.HerbsAndPlants, PinIconType.Dot, new string[2] { "Pickable_Thistle", "Thistle" }, new string[1] { "$item_thistle" }, 10f, (GathererConfig cfg) => cfg.TrackHerbsAndPlants.Value && cfg.MarkThistle.Value));
			Register(new ResourceDefinition("Dandelion", "Dandelion", "Dandelion", ResourceCategory.HerbsAndPlants, PinIconType.Dot, new string[2] { "Pickable_Dandelion", "Dandelion" }, new string[1] { "$item_dandelion" }, 10f, (GathererConfig cfg) => cfg.TrackHerbsAndPlants.Value && cfg.MarkDandelion.Value));
			Register(new ResourceDefinition("CarrotSeeds", "Carrot Seeds", "Carrot Seeds", ResourceCategory.HerbsAndPlants, PinIconType.Dot, new string[2] { "Pickable_SeedCarrot", "CarrotSeeds" }, new string[1] { "$item_carrotseeds" }, 10f, (GathererConfig cfg) => cfg.TrackHerbsAndPlants.Value && cfg.MarkCarrotSeeds.Value));
			Register(new ResourceDefinition("TurnipSeeds", "Turnip Seeds", "Turnip Seeds", ResourceCategory.HerbsAndPlants, PinIconType.Dot, new string[2] { "Pickable_SeedTurnip", "TurnipSeeds" }, new string[1] { "$item_turnipseeds" }, 10f, (GathererConfig cfg) => cfg.TrackHerbsAndPlants.Value && cfg.MarkTurnipSeeds.Value));
			Register(new ResourceDefinition("OnionSeeds", "Onion Seeds", "Onion Seeds", ResourceCategory.HerbsAndPlants, PinIconType.Dot, new string[2] { "Pickable_SeedOnion", "OnionSeeds" }, new string[1] { "$item_onionseeds" }, 10f, (GathererConfig cfg) => cfg.TrackHerbsAndPlants.Value && cfg.MarkOnionSeeds.Value));
			Register(new ResourceDefinition("Fiddlehead", "Fiddlehead", "Fiddlehead", ResourceCategory.HerbsAndPlants, PinIconType.Dot, new string[2] { "Pickable_Fiddlehead", "Fiddlehead" }, new string[1] { "$item_fiddlehead" }, 10f, (GathererConfig cfg) => cfg.TrackHerbsAndPlants.Value && cfg.MarkFiddlehead.Value));
			Register(new ResourceDefinition("Barley", "Barley", "Barley", ResourceCategory.FarmingCrops, PinIconType.Dot, new string[3] { "Pickable_Barley", "Pickable_Barley_Wild", "Barley" }, new string[1] { "$item_barley" }, 10f, (GathererConfig cfg) => cfg.TrackFarmingCrops.Value && cfg.MarkBarley.Value));
			Register(new ResourceDefinition("Flax", "Flax", "Flax", ResourceCategory.FarmingCrops, PinIconType.Dot, new string[3] { "Pickable_Flax", "Pickable_Flax_Wild", "Flax" }, new string[1] { "$item_flax" }, 10f, (GathererConfig cfg) => cfg.TrackFarmingCrops.Value && cfg.MarkFlax.Value));
			Register(new ResourceDefinition("Copper", "Copper Deposit", "Copper", ResourceCategory.OresAndVeins, PinIconType.Hammer, new string[3] { "rock4_copper", "MineRock_Copper", "copper" }, new string[1] { "$piece_deposit_copper" }, 20f, (GathererConfig cfg) => cfg.TrackOresAndVeins.Value && cfg.MarkCopper.Value));
			Register(new ResourceDefinition("Tin", "Tin Deposit", "Tin", ResourceCategory.OresAndVeins, PinIconType.Hammer, new string[2] { "mine_rock_tin", "tin" }, new string[1] { "$piece_deposit_tin" }, 15f, (GathererConfig cfg) => cfg.TrackOresAndVeins.Value && cfg.MarkTin.Value));
			Register(new ResourceDefinition("Silver", "Silver Vein", "Silver", ResourceCategory.OresAndVeins, PinIconType.Hammer, new string[3] { "silvervein", "rock3_silver", "silver" }, new string[1] { "$piece_deposit_silver" }, 20f, (GathererConfig cfg) => cfg.TrackOresAndVeins.Value && cfg.MarkSilver.Value));
			Register(new ResourceDefinition("IronMudpile", "Muddy Scrap Pile", "Muddy Scrap Pile", ResourceCategory.OresAndVeins, PinIconType.Hammer, new string[3] { "mudpile", "mudpile2", "iron" }, new string[1] { "$piece_mudpile" }, 15f, (GathererConfig cfg) => cfg.TrackOresAndVeins.Value && cfg.MarkIronMudpile.Value));
			Register(new ResourceDefinition("Obsidian", "Obsidian Deposit", "Obsidian", ResourceCategory.OresAndVeins, PinIconType.Hammer, new string[3] { "MineRock_Obsidian", "rock4_forest_fracturing", "obsidian" }, new string[1] { "$piece_deposit_obsidian" }, 15f, (GathererConfig cfg) => cfg.TrackOresAndVeins.Value && cfg.MarkObsidian.Value));
			Register(new ResourceDefinition("Flametal", "Flametal Ore", "Flametal", ResourceCategory.OresAndVeins, PinIconType.Hammer, new string[2] { "MineRock_Meteorite", "flametal" }, new string[1] { "$piece_deposit_flametal" }, 20f, (GathererConfig cfg) => cfg.TrackOresAndVeins.Value && cfg.MarkFlametal.Value));
			Register(new ResourceDefinition("Beehive", "Wild Beehive", "Beehive", ResourceCategory.Beehives, PinIconType.Fireplace, new string[1] { "Beehive" }, new string[1] { "$piece_beehive" }, 15f, (GathererConfig cfg) => cfg.TrackBeehives.Value && cfg.MarkBeehive.Value));
			Register(new ResourceDefinition("Vegvisir", "Vegvisir", "Vegvisir", ResourceCategory.Special, PinIconType.Dot, new string[1] { "Vegvisir" }, new string[1] { "$piece_vegvisir" }, 15f, (GathererConfig cfg) => cfg.TrackSpecial.Value && cfg.MarkVegvisir.Value));
			Register(new ResourceDefinition("SurtlingSpawner", "Surtling Spawner", "Surtling Spawner", ResourceCategory.Special, PinIconType.Fireplace, new string[2] { "Spawner_FireHole", "FireFlies_FireHole" }, new string[2] { "$piece_surtlingspawner", "$piece_firehole" }, 15f, (GathererConfig cfg) => cfg.TrackSpecial.Value && cfg.MarkSurtlingSpawner.Value));
			Register(new ResourceDefinition("AncientRoot", "Ancient Root", "Ancient Root", ResourceCategory.Special, PinIconType.Dot, new string[1] { "ResourceRoot" }, new string[1] { "$piece_resourceroot" }, 20f, (GathererConfig cfg) => cfg.TrackSpecial.Value && cfg.MarkAncientRoot.Value));
		}

		public static void Register(ResourceDefinition def)
		{
			Definitions.Add(def);
		}

		public static ResourceDefinition? Match(string prefabName, string hoverName, string localizedName)
		{
			foreach (ResourceDefinition definition in Definitions)
			{
				if (definition.Matches(prefabName, hoverName, localizedName))
				{
					return definition;
				}
			}
			return null;
		}

		public static bool IsEnabled(ResourceDefinition def, GathererConfig config, string? prefabName = null, string? localizedName = null)
		{
			if (!config.Enabled.Value)
			{
				return false;
			}
			if (config.IsCustomExcluded(def.Id) || config.IsCustomExcluded(def.DisplayName) || config.IsCustomExcluded(def.CleanShortName) || (!string.IsNullOrEmpty(prefabName) && config.IsCustomExcluded(prefabName)) || (!string.IsNullOrEmpty(localizedName) && config.IsCustomExcluded(localizedName)))
			{
				return false;
			}
			if (config.IsCustomIncluded(def.Id) || config.IsCustomIncluded(def.DisplayName) || config.IsCustomIncluded(def.CleanShortName) || (!string.IsNullOrEmpty(prefabName) && config.IsCustomIncluded(prefabName)) || (!string.IsNullOrEmpty(localizedName) && config.IsCustomIncluded(localizedName)))
			{
				return true;
			}
			return def.IsEnabledFunc(config);
		}
	}
}
namespace ValheimGatherer.Configuration
{
	public class GathererConfig
	{
		private readonly Dictionary<string, ConfigEntry<bool>> _resourceVisibility = new Dictionary<string, ConfigEntry<bool>>();

		private HashSet<string> _parsedIncludes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private HashSet<string> _parsedExcludes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		public ConfigEntry<bool> Enabled { get; private set; }

		public ConfigEntry<KeyCode> ToggleUiKey { get; private set; }

		public ConfigEntry<DiscoveryMode> Mode { get; private set; }

		public ConfigEntry<bool> ShareOnCartographyTable { get; private set; }

		public ConfigEntry<bool> ShowHudNotification { get; private set; }

		public ConfigEntry<string> PinNamePrefix { get; private set; }

		public ConfigEntry<bool> CleanPinNames { get; private set; }

		public ConfigEntry<PinIconType> DefaultPinIcon { get; private set; }

		public ConfigEntry<PinIconType> OrePinIcon { get; private set; }

		public ConfigEntry<PinIconType> SpecialPinIcon { get; private set; }

		public ConfigEntry<float> HerbMergeRadius { get; private set; }

		public ConfigEntry<float> OreMergeRadius { get; private set; }

		public ConfigEntry<float> SpecialMergeRadius { get; private set; }

		public ConfigEntry<float> ProximityRadius { get; private set; }

		public ConfigEntry<float> ProximityScanInterval { get; private set; }

		public ConfigEntry<bool> TrackMushrooms { get; private set; }

		public ConfigEntry<bool> TrackBerries { get; private set; }

		public ConfigEntry<bool> TrackHerbsAndPlants { get; private set; }

		public ConfigEntry<bool> TrackFarmingCrops { get; private set; }

		public ConfigEntry<bool> TrackOresAndVeins { get; private set; }

		public ConfigEntry<bool> TrackBeehives { get; private set; }

		public ConfigEntry<bool> TrackSpecial { get; private set; }

		public ConfigEntry<bool> MarkRedMushroom { get; private set; }

		public ConfigEntry<bool> MarkYellowMushroom { get; private set; }

		public ConfigEntry<bool> MarkBlueMushroom { get; private set; }

		public ConfigEntry<bool> MarkMagecap { get; private set; }

		public ConfigEntry<bool> MarkJotunPuffs { get; private set; }

		public ConfigEntry<bool> MarkSmokePuff { get; private set; }

		public ConfigEntry<bool> MarkRaspberry { get; private set; }

		public ConfigEntry<bool> MarkBlueberry { get; private set; }

		public ConfigEntry<bool> MarkCloudberry { get; private set; }

		public ConfigEntry<bool> MarkThistle { get; private set; }

		public ConfigEntry<bool> MarkDandelion { get; private set; }

		public ConfigEntry<bool> MarkCarrotSeeds { get; private set; }

		public ConfigEntry<bool> MarkTurnipSeeds { get; private set; }

		public ConfigEntry<bool> MarkOnionSeeds { get; private set; }

		public ConfigEntry<bool> MarkFiddlehead { get; private set; }

		public ConfigEntry<bool> MarkBarley { get; private set; }

		public ConfigEntry<bool> MarkFlax { get; private set; }

		public ConfigEntry<bool> MarkCopper { get; private set; }

		public ConfigEntry<bool> MarkTin { get; private set; }

		public ConfigEntry<bool> MarkSilver { get; private set; }

		public ConfigEntry<bool> MarkIronMudpile { get; private set; }

		public ConfigEntry<bool> MarkObsidian { get; private set; }

		public ConfigEntry<bool> MarkFlametal { get; private set; }

		public ConfigEntry<bool> MarkBeehive { get; private set; }

		public ConfigEntry<bool> MarkVegvisir { get; private set; }

		public ConfigEntry<bool> MarkSurtlingSpawner { get; private set; }

		public ConfigEntry<bool> MarkAncientRoot { get; private set; }

		public ConfigEntry<string> CustomIncludeFilter { get; private set; }

		public ConfigEntry<string> CustomExcludeFilter { get; private set; }

		public ConfigEntry<bool> UseResourceIcons { get; private set; }

		public IReadOnlyDictionary<string, ConfigEntry<bool>> ResourceVisibility => _resourceVisibility;

		public GathererConfig(ConfigFile config)
		{
			InitConfig(config);
			UseResourceIcons = config.Bind<bool>("10 - Map Display", "UseResourceIcons", true, "Display item images on resource pins recognized by name. Saved/shared pins retain their standard icons.");
			foreach (ResourceDefinition allDefinition in ResourceRegistry.AllDefinitions)
			{
				_resourceVisibility[allDefinition.Id] = config.Bind<bool>("11 - Resource Visibility", allDefinition.Id, true, "Show " + allDefinition.DisplayName + " pins on the world map and minimap. Does not change tracking, saving or sharing.");
			}
			UpdateParsedFilters();
			config.ConfigReloaded += delegate
			{
				UpdateParsedFilters();
			};
		}

		private void InitConfig(ConfigFile config)
		{
			Enabled = config.Bind<bool>("0 - General", "Enabled", true, "Master switch to enable or disable the Gatherer mod.");
			ToggleUiKey = config.Bind<KeyCode>("0 - General", "ToggleUiKey", (KeyCode)289, "Keyboard shortcut to open and close the interactive in-game Gatherer resource tracking menu (Default: F8).");
			Mode = config.Bind<DiscoveryMode>("0 - General", "DiscoveryMode", DiscoveryMode.InteractAndProximity, "Discovery mode: InteractOnly (when picked/mined), InteractAndProximity (auto-marks nearby nodes), InteractAndHover (when looking at nodes), or All.");
			ShareOnCartographyTable = config.Bind<bool>("0 - General", "ShareOnCartographyTable", true, "When true, markings are saved and automatically shared to other players via the in-game Cartography Table.");
			ShowHudNotification = config.Bind<bool>("0 - General", "ShowHudNotification", true, "Display a notification in top-left HUD when a new resource is marked.");
			PinNamePrefix = config.Bind<string>("0 - General", "PinNamePrefix", "", "Optional prefix added to pin names (e.g. '[G] ' or empty for clean name).");
			CleanPinNames = config.Bind<bool>("0 - General", "CleanPinNames", true, "Shortens redundant names (e.g. 'Copper' instead of 'Copper deposit', 'Tin' instead of 'Tin deposit').");
			DefaultPinIcon = config.Bind<PinIconType>("1 - Pin Settings", "DefaultPinIcon", PinIconType.Dot, "Pin icon used for general resources like mushrooms, berries, and herbs (Dot, Fireplace, House, Hammer, Portal).");
			OrePinIcon = config.Bind<PinIconType>("1 - Pin Settings", "OrePinIcon", PinIconType.Hammer, "Pin icon used for ore deposits and mineral veins.");
			SpecialPinIcon = config.Bind<PinIconType>("1 - Pin Settings", "SpecialPinIcon", PinIconType.Fireplace, "Pin icon used for special POIs like wild beehives and vegvisirs.");
			HerbMergeRadius = config.Bind<float>("1 - Pin Settings", "HerbMergeRadius", 10f, "Minimum distance in meters between pins of the same herb/mushroom/berry. Prevents duplicate pins within clusters.");
			OreMergeRadius = config.Bind<float>("1 - Pin Settings", "OreMergeRadius", 20f, "Minimum distance in meters between pins of the same ore deposit. Prevents duplicate pins for large veins.");
			SpecialMergeRadius = config.Bind<float>("1 - Pin Settings", "SpecialMergeRadius", 15f, "Minimum distance in meters for special POIs like beehives.");
			ProximityRadius = config.Bind<float>("2 - Proximity Radar", "ProximityRadius", 15f, "Radius around the player to scan for unpinned resources when using proximity discovery (WoW Gatherer radar style).");
			ProximityScanInterval = config.Bind<float>("2 - Proximity Radar", "ProximityScanInterval", 2f, "Interval in seconds between proximity scans. Higher values improve performance, lower values spot nodes faster.");
			TrackMushrooms = config.Bind<bool>("3 - Categories", "TrackMushrooms", false, "Enable or disable tracking all mushrooms.");
			TrackBerries = config.Bind<bool>("3 - Categories", "TrackBerries", false, "Enable or disable tracking all berries.");
			TrackHerbsAndPlants = config.Bind<bool>("3 - Categories", "TrackHerbsAndPlants", false, "Enable or disable tracking wild plants and herbs.");
			TrackFarmingCrops = config.Bind<bool>("3 - Categories", "TrackFarmingCrops", false, "Enable or disable tracking wild and cultivated crops (e.g. barley, flax).");
			TrackOresAndVeins = config.Bind<bool>("3 - Categories", "TrackOresAndVeins", false, "Enable or disable tracking all ore veins and mineral deposits.");
			TrackBeehives = config.Bind<bool>("3 - Categories", "TrackBeehives", false, "Enable or disable tracking wild beehives.");
			TrackSpecial = config.Bind<bool>("3 - Categories", "TrackSpecial", false, "Enable or disable tracking special POIs (vegvisir, surtling spawner, ancient roots).");
			MarkRedMushroom = config.Bind<bool>("4 - Specific Resources - Mushrooms", "RedMushroom", false, "Mark standard red mushrooms.");
			MarkYellowMushroom = config.Bind<bool>("4 - Specific Resources - Mushrooms", "YellowMushroom", false, "Mark yellow mushrooms found in dungeons, caves, and crypts.");
			MarkBlueMushroom = config.Bind<bool>("4 - Specific Resources - Mushrooms", "BlueMushroom", false, "Mark blue mushrooms.");
			MarkMagecap = config.Bind<bool>("4 - Specific Resources - Mushrooms", "Magecap", false, "Mark Magecap mushrooms (Mistlands).");
			MarkJotunPuffs = config.Bind<bool>("4 - Specific Resources - Mushrooms", "JotunPuffs", false, "Mark Jotun Puffs mushrooms (Mistlands).");
			MarkSmokePuff = config.Bind<bool>("4 - Specific Resources - Mushrooms", "SmokePuff", false, "Mark Smoke Puff mushrooms (Ashlands).");
			MarkRaspberry = config.Bind<bool>("5 - Specific Resources - Berries", "Raspberry", false, "Mark raspberry bushes (Meadows).");
			MarkBlueberry = config.Bind<bool>("5 - Specific Resources - Berries", "Blueberry", false, "Mark blueberry bushes (Black Forest).");
			MarkCloudberry = config.Bind<bool>("5 - Specific Resources - Berries", "Cloudberry", false, "Mark cloudberry bushes (Plains).");
			MarkThistle = config.Bind<bool>("6 - Specific Resources - Herbs and Plants", "Thistle", false, "Mark glowing thistle (Black Forest / Swamp).");
			MarkDandelion = config.Bind<bool>("6 - Specific Resources - Herbs and Plants", "Dandelion", false, "Mark dandelions (Meadows).");
			MarkCarrotSeeds = config.Bind<bool>("6 - Specific Resources - Herbs and Plants", "CarrotSeeds", false, "Mark wild seed carrots (Black Forest).");
			MarkTurnipSeeds = config.Bind<bool>("6 - Specific Resources - Herbs and Plants", "TurnipSeeds", false, "Mark wild seed turnips (Swamp).");
			MarkOnionSeeds = config.Bind<bool>("6 - Specific Resources - Herbs and Plants", "OnionSeeds", false, "Mark wild seed onions (Mountain chests/wild).");
			MarkFiddlehead = config.Bind<bool>("6 - Specific Resources - Herbs and Plants", "Fiddlehead", false, "Mark fiddleheads (Ashlands).");
			MarkBarley = config.Bind<bool>("6 - Specific Resources - Herbs and Plants", "Barley", false, "Mark barley (Plains).");
			MarkFlax = config.Bind<bool>("6 - Specific Resources - Herbs and Plants", "Flax", false, "Mark flax (Plains).");
			MarkCopper = config.Bind<bool>("7 - Specific Resources - Ores", "CopperDeposit", false, "Mark copper deposits (Black Forest). Set to true if you want to track copper!");
			MarkTin = config.Bind<bool>("7 - Specific Resources - Ores", "TinDeposit", false, "Mark tin deposits (Black Forest shorelines).");
			MarkSilver = config.Bind<bool>("7 - Specific Resources - Ores", "SilverVein", false, "Mark silver veins (Mountains).");
			MarkIronMudpile = config.Bind<bool>("7 - Specific Resources - Ores", "IronMuddyScrapPile", false, "Mark muddy scrap piles (Swamp Sunken Crypts / Swamp ground).");
			MarkObsidian = config.Bind<bool>("7 - Specific Resources - Ores", "Obsidian", false, "Mark obsidian deposits (Mountains).");
			MarkFlametal = config.Bind<bool>("7 - Specific Resources - Ores", "FlametalOre", false, "Mark flametal / meteorite ore deposits (Ashlands).");
			MarkBeehive = config.Bind<bool>("8 - Specific Resources - Special", "Beehive", false, "Mark wild beehives found in abandoned buildings.");
			MarkVegvisir = config.Bind<bool>("8 - Specific Resources - Special", "Vegvisir", false, "Mark Vegvisir runestones.");
			MarkSurtlingSpawner = config.Bind<bool>("8 - Specific Resources - Special", "SurtlingSpawner", false, "Mark fire geysers / surtling spawners (Swamp / Ashlands).");
			MarkAncientRoot = config.Bind<bool>("8 - Specific Resources - Special", "AncientRoot", false, "Mark ancient roots / sap roots (Mistlands).");
			CustomIncludeFilter = config.Bind<string>("9 - Advanced Filters", "CustomIncludeFilter", "", "Comma-separated list of prefab names or localized names to always mark, e.g. 'DragonEgg, GoblinTotem'.");
			CustomExcludeFilter = config.Bind<string>("9 - Advanced Filters", "CustomExcludeFilter", "", "Comma-separated list of prefab names or localized names to never mark, e.g. 'Copper, Stone, Flint'.");
			CustomIncludeFilter.SettingChanged += delegate
			{
				UpdateParsedFilters();
			};
			CustomExcludeFilter.SettingChanged += delegate
			{
				UpdateParsedFilters();
			};
		}

		private void UpdateParsedFilters()
		{
			_parsedIncludes = ParseFilterString(CustomIncludeFilter?.Value);
			_parsedExcludes = ParseFilterString(CustomExcludeFilter?.Value);
		}

		public static HashSet<string> ParseFilterString(string? filter)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(filter))
			{
				return hashSet;
			}
			string[] array = filter.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (!string.IsNullOrEmpty(text))
				{
					hashSet.Add(text);
				}
			}
			return hashSet;
		}

		public bool IsCustomIncluded(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			return _parsedIncludes.Contains(name);
		}

		public bool IsCustomExcluded(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			return _parsedExcludes.Contains(name);
		}
	}
	public enum ResourceCategory
	{
		Mushrooms,
		Berries,
		HerbsAndPlants,
		FarmingCrops,
		OresAndVeins,
		Beehives,
		Special,
		Custom
	}
	public enum DiscoveryMode
	{
		InteractOnly,
		InteractAndProximity,
		InteractAndHover,
		All
	}
	public enum PinIconType
	{
		Dot = 3,
		Fireplace = 0,
		House = 1,
		Hammer = 2,
		Portal = 6
	}
}