Decompiled source of Lookout v1.0.1

Lookout.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
using ValheimModShared;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimModShared
{
	internal static class ConfigWatcher
	{
		public static void Watch(ConfigFile config, ManualLogSource log)
		{
			if (config == null)
			{
				return;
			}
			string path = config.ConfigFilePath;
			string directoryName = Path.GetDirectoryName(path);
			string fileName = Path.GetFileName(path);
			if (string.IsNullOrEmpty(directoryName) || string.IsNullOrEmpty(fileName))
			{
				return;
			}
			FileSystemWatcher obj = new FileSystemWatcher(directoryName, fileName)
			{
				NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
				IncludeSubdirectories = false,
				SynchronizingObject = null
			};
			FileSystemEventHandler reload = delegate
			{
				if (!File.Exists(path))
				{
					return;
				}
				try
				{
					config.Reload();
					ManualLogSource obj2 = log;
					if (obj2 != null)
					{
						obj2.LogInfo((object)"Config reloaded from disk");
					}
				}
				catch (Exception ex)
				{
					ManualLogSource obj3 = log;
					if (obj3 != null)
					{
						obj3.LogError((object)("Could not reload config; check its format. " + ex.Message));
					}
				}
			};
			obj.Changed += reload;
			obj.Created += reload;
			obj.Renamed += delegate(object s, RenamedEventArgs e)
			{
				reload(s, e);
			};
			obj.EnableRaisingEvents = true;
		}
	}
}
namespace Lookout
{
	[Flags]
	internal enum PoiSource
	{
		None = 0,
		Deposit = 1,
		Pickable = 2,
		Breakable = 4
	}
	internal sealed class CatalogEntry
	{
		public string Key;

		public string Name;

		public Sprite Icon;

		public PoiSource Sources;

		public int Nearby;
	}
	internal static class ResourceRules
	{
		public struct Yield
		{
			public ItemData Item;

			public PoiSource Source;
		}

		private static readonly HashSet<string> Bulk = new HashSet<string>(StringComparer.Ordinal) { "$item_stone", "$item_wood", "$item_finewood", "$item_roundlog", "$item_elderbark", "$item_blackwood" };

		public static string Collect(GameObject go, List<Yield> into)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Invalid comparison between Unknown and I4
			string result = null;
			Pickable component = go.GetComponent<Pickable>();
			if ((Object)(object)component != (Object)null)
			{
				ItemData val = ItemOf(component.m_itemPrefab);
				if (val != null && !Bulk.Contains(val.m_shared.m_name))
				{
					into.Add(new Yield
					{
						Item = val,
						Source = PoiSource.Pickable
					});
				}
				if (!string.IsNullOrEmpty(component.m_overrideName))
				{
					result = component.m_overrideName;
				}
				return result;
			}
			MineRock5 component2 = go.GetComponent<MineRock5>();
			if ((Object)(object)component2 != (Object)null)
			{
				AddDrops(component2.m_dropItems, PoiSource.Deposit, into);
				return component2.m_name;
			}
			MineRock component3 = go.GetComponent<MineRock>();
			if ((Object)(object)component3 != (Object)null)
			{
				AddDrops(component3.m_dropItems, PoiSource.Deposit, into);
				return component3.m_name;
			}
			Destructible component4 = go.GetComponent<Destructible>();
			if ((Object)(object)component4 != (Object)null && (int)component4.m_destructibleType == 1)
			{
				GameObject spawnWhenDestroyed = component4.m_spawnWhenDestroyed;
				if ((Object)(object)spawnWhenDestroyed != (Object)null)
				{
					MineRock5 component5 = spawnWhenDestroyed.GetComponent<MineRock5>();
					if ((Object)(object)component5 != (Object)null)
					{
						AddDrops(component5.m_dropItems, PoiSource.Deposit, into);
						return component5.m_name;
					}
					MineRock component6 = spawnWhenDestroyed.GetComponent<MineRock>();
					if ((Object)(object)component6 != (Object)null)
					{
						AddDrops(component6.m_dropItems, PoiSource.Deposit, into);
						return component6.m_name;
					}
				}
				DropOnDestroyed component7 = go.GetComponent<DropOnDestroyed>();
				if ((Object)(object)component7 != (Object)null)
				{
					AddDrops(component7.m_dropWhenDestroyed, PoiSource.Breakable, into);
				}
			}
			return result;
		}

		private static void AddDrops(DropTable table, PoiSource source, List<Yield> into)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (table?.m_drops == null)
			{
				return;
			}
			foreach (DropData drop in table.m_drops)
			{
				ItemData val = ItemOf(drop.m_item);
				if (val != null && !Bulk.Contains(val.m_shared.m_name))
				{
					into.Add(new Yield
					{
						Item = val,
						Source = source
					});
				}
			}
		}

		private static ItemData ItemOf(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			ItemDrop component = prefab.GetComponent<ItemDrop>();
			ItemData val = (((Object)(object)component != (Object)null) ? component.m_itemData : null);
			if (val?.m_shared == null || string.IsNullOrEmpty(val.m_shared.m_name))
			{
				return null;
			}
			return val;
		}
	}
	internal static class Catalog
	{
		private static readonly Dictionary<string, CatalogEntry> s_entries = new Dictionary<string, CatalogEntry>(StringComparer.Ordinal);

		private static readonly List<ResourceRules.Yield> s_scratch = new List<ResourceRules.Yield>();

		private static int s_scannedPrefabCount = -1;

		public static IEnumerable<CatalogEntry> Entries => s_entries.Values;

		public static event Action Changed;

		public static bool TryGet(string key, out CatalogEntry entry)
		{
			return s_entries.TryGetValue(key, out entry);
		}

		public static void EnsureScanned()
		{
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null || instance.m_prefabs == null || instance.m_prefabs.Count == s_scannedPrefabCount)
			{
				return;
			}
			s_scannedPrefabCount = instance.m_prefabs.Count;
			int count = s_entries.Count;
			foreach (GameObject prefab in instance.m_prefabs)
			{
				if ((Object)(object)prefab == (Object)null)
				{
					continue;
				}
				try
				{
					s_scratch.Clear();
					ResourceRules.Collect(prefab, s_scratch);
					foreach (ResourceRules.Yield item in s_scratch)
					{
						Register(item.Item, item.Source, raise: false);
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogDebug((object)("Catalog: skipped " + ((Object)prefab).name + ": " + ex.Message));
				}
			}
			Plugin.Log.LogDebug((object)$"Catalog: {s_entries.Count} pinnable items from {s_scannedPrefabCount} prefabs");
			if (s_entries.Count != count)
			{
				Catalog.Changed?.Invoke();
			}
		}

		public static CatalogEntry Register(ItemData item, PoiSource source, bool raise = true)
		{
			string name = item.m_shared.m_name;
			if (!s_entries.TryGetValue(name, out var value))
			{
				value = new CatalogEntry
				{
					Key = name,
					Name = Localize(name),
					Icon = SafeIcon(item),
					Sources = source
				};
				s_entries.Add(name, value);
				if (raise)
				{
					Catalog.Changed?.Invoke();
				}
			}
			else
			{
				value.Sources |= source;
				if ((Object)(object)value.Icon == (Object)null)
				{
					value.Icon = SafeIcon(item);
				}
			}
			return value;
		}

		public static void ResetNearbyCounts()
		{
			foreach (CatalogEntry value in s_entries.Values)
			{
				value.Nearby = 0;
			}
		}

		private static Sprite SafeIcon(ItemData item)
		{
			try
			{
				return item.GetIcon();
			}
			catch
			{
				return null;
			}
		}

		internal static string Localize(string token)
		{
			Localization instance = Localization.instance;
			if (instance == null || string.IsNullOrEmpty(token))
			{
				return token ?? string.Empty;
			}
			string text = instance.Localize(token);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return token;
		}
	}
	internal static class Icons
	{
		private static Sprite s_dungeon;

		private static Sprite s_location;

		private static Sprite s_generic;

		public static Sprite Dungeon => s_dungeon ?? (s_dungeon = Load("dungeon.png"));

		public static Sprite Location => s_location ?? (s_location = Load("location.png"));

		public static Sprite Generic => s_generic ?? (s_generic = Load("generic.png"));

		private static Sprite Load(string resourceName)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
				if (stream == null)
				{
					Plugin.Log.LogWarning((object)("Embedded " + resourceName + " not found."));
					return null;
				}
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				Texture2D val = AssetUtils.LoadImage(memoryStream.ToArray());
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)("Embedded " + resourceName + " could not be decoded."));
					return null;
				}
				((Texture)val).filterMode = (FilterMode)1;
				Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
				((Object)obj).name = "Lookout." + resourceName;
				return obj;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not load " + resourceName + ": " + ex.Message));
				return null;
			}
		}
	}
	internal sealed class LookoutPanel : MonoBehaviour
	{
		private sealed class Row
		{
			public CatalogEntry Entry;

			public GameObject Root;

			public Toggle Toggle;

			public Text Nearby;
		}

		private const float PanelWidth = 560f;

		private const float PanelHeight = 680f;

		private const float RowHeight = 40f;

		private GameObject _panel;

		private InputField _filter;

		private Transform _content;

		private Text _summary;

		private Toggle _dungeons;

		private Toggle _locations;

		private Toggle _buried;

		private Toggle _explored;

		private Toggle _discovered;

		private readonly List<Row> _rows = new List<Row>();

		private bool _dirty = true;

		private bool _syncRequested;

		private bool _builtDiscoveredOnly;

		private float _nextCountRefresh;

		private GameObject _mapButton;

		private static Settings S => Plugin.Settings;

		public bool IsOpen
		{
			get
			{
				if ((Object)(object)_panel != (Object)null)
				{
					return _panel.activeSelf;
				}
				return false;
			}
		}

		private void OnEnable()
		{
			Catalog.Changed += MarkDirty;
			S.Changed += OnSettingsChanged;
		}

		private void OnDisable()
		{
			Catalog.Changed -= MarkDirty;
			S.Changed -= OnSettingsChanged;
			if ((Object)(object)_panel != (Object)null)
			{
				Object.Destroy((Object)(object)_panel);
			}
			if ((Object)(object)_mapButton != (Object)null)
			{
				Object.Destroy((Object)(object)_mapButton);
			}
			GUIManager.BlockInput(false);
		}

		private void Update()
		{
			if (!IsOpen)
			{
				return;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null || ((Object)(object)Menu.instance != (Object)null && Menu.IsVisible()))
			{
				SetOpen(open: false);
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				SetOpen(open: false);
				return;
			}
			if (_dirty)
			{
				_dirty = false;
				_syncRequested = false;
				RebuildRows();
			}
			else if (_syncRequested)
			{
				_syncRequested = false;
				SyncRows();
			}
			if (!(Time.unscaledTime >= _nextCountRefresh))
			{
				return;
			}
			_nextCountRefresh = Time.unscaledTime + 0.5f;
			foreach (Row row in _rows)
			{
				row.Nearby.text = ((row.Entry.Nearby > 0) ? row.Entry.Nearby.ToString() : string.Empty);
			}
		}

		public void Toggle()
		{
			SetOpen(!IsOpen);
		}

		public void SetOpen(bool open)
		{
			if (open)
			{
				if ((Object)(object)GUIManager.CustomGUIFront == (Object)null || GUIManager.Instance == null)
				{
					Plugin.Log.LogWarning((object)"GUI not ready yet; cannot open the Lookout panel.");
					return;
				}
				if ((Object)(object)_panel == (Object)null)
				{
					try
					{
						BuildPanel();
					}
					catch (Exception arg)
					{
						Plugin.Log.LogError((object)$"Failed to build the Lookout panel: {arg}");
						return;
					}
				}
				Catalog.EnsureScanned();
				_dirty = true;
				_panel.SetActive(true);
				SyncCategoryToggles();
				GUIManager.BlockInput(true);
			}
			else if ((Object)(object)_panel != (Object)null && _panel.activeSelf)
			{
				_panel.SetActive(false);
				GUIManager.BlockInput(false);
			}
		}

		public void EnsureMapButton(Minimap map)
		{
			//IL_0080: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			if (!S.MapButton.Value)
			{
				if ((Object)(object)_mapButton != (Object)null)
				{
					Object.Destroy((Object)(object)_mapButton);
					_mapButton = null;
				}
			}
			else if (!((Object)(object)_mapButton != (Object)null) && !((Object)(object)map == (Object)null) && !((Object)(object)map.m_largeRoot == (Object)null) && GUIManager.Instance != null)
			{
				try
				{
					_mapButton = GUIManager.Instance.CreateButton("Lookout", map.m_largeRoot.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(96f, -28f), 150f, 36f);
					((Object)_mapButton).name = "Lookout.MapButton";
					((UnityEvent)_mapButton.GetComponent<Button>().onClick).AddListener(new UnityAction(Toggle));
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Could not add the map button: " + ex.Message));
				}
			}
		}

		private void MarkDirty()
		{
			_dirty = true;
		}

		private void OnSettingsChanged()
		{
			if (S.OnlyDiscoveredItems.Value != _builtDiscoveredOnly)
			{
				_dirty = true;
			}
			else
			{
				_syncRequested = true;
			}
		}

		private void SyncRows()
		{
			SyncCategoryToggles();
			foreach (Row row in _rows)
			{
				row.Toggle.SetIsOnWithoutNotify(S.IsItemEnabled(row.Entry.Key));
			}
			UpdateSummary();
		}

		private void BuildPanel()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0084: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_040b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Expected O, but got Unknown
			GUIManager instance = GUIManager.Instance;
			_panel = instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 560f, 680f, true);
			((Object)_panel).name = "Lookout.Panel";
			GameObject obj = instance.CreateText("Lookout", _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -34f), instance.NorseBold, 26, instance.ValheimOrange, true, Color.black, 560f, 40f, false);
			obj.GetComponent<RectTransform>().pivot = new Vector2(0.5f, 0.5f);
			obj.GetComponent<Text>().alignment = (TextAnchor)4;
			((UnityEvent)instance.CreateButton("X", _panel.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-30f, -30f), 36f, 36f).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				SetOpen(open: false);
			});
			float num = -76f;
			_dungeons = CreateLabeledToggle("Dungeon Entrances", 30f, num, delegate(bool v)
			{
				S.ShowDungeons.Value = v;
			});
			_locations = CreateLabeledToggle("Other Locations", 290f, num, delegate(bool v)
			{
				S.ShowOtherLocations.Value = v;
			});
			num -= 34f;
			_buried = CreateLabeledToggle("Buried Deposits", 30f, num, delegate(bool v)
			{
				S.ShowBuried.Value = v;
			});
			_explored = CreateLabeledToggle("Only Explored Map", 290f, num, delegate(bool v)
			{
				S.OnlyExploredAreas.Value = v;
			});
			num -= 34f;
			_discovered = CreateLabeledToggle("Only Discovered Items", 30f, num, delegate(bool v)
			{
				S.OnlyDiscoveredItems.Value = v;
			});
			num -= 44f;
			GameObject val = instance.CreateInputField(_panel.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(280f, num), (ContentType)0, "Filter items...", 16, 500f, 32f);
			_filter = val.GetComponent<InputField>();
			((UnityEvent<string>)(object)_filter.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				MarkDirty();
			});
			num -= 30f;
			GameObject val2 = instance.CreateText("", _panel.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(30f, num), instance.AveriaSerif, 14, instance.ValheimBeige, true, Color.black, 500f, 20f, false);
			AlignLeft(val2);
			_summary = val2.GetComponent<Text>();
			num -= 14f;
			float num2 = 680f + num - 30f;
			GameObject val3 = instance.CreateScrollView(_panel.transform, false, true, 10f, 6f, ColorBlock.defaultColorBlock, new Color(0f, 0f, 0f, 0.35f), 500f, num2);
			RectTransform component = val3.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(0f, 1f);
			component.pivot = new Vector2(0f, 1f);
			component.anchoredPosition = new Vector2(30f, num);
			_content = (Transform)(object)val3.GetComponentInChildren<ScrollRect>().content;
			VerticalLayoutGroup obj2 = ((Component)_content).GetComponent<VerticalLayoutGroup>() ?? ((Component)_content).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 2f;
			((LayoutGroup)obj2).padding = new RectOffset(4, 4, 4, 4);
			_panel.SetActive(false);
		}

		private Toggle CreateLabeledToggle(string label, float x, float y, Action<bool> onChanged)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			GUIManager instance = GUIManager.Instance;
			GameObject obj = instance.CreateToggle(_panel.transform, 24f, 24f);
			RectTransform component = obj.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(0f, 1f);
			component.pivot = new Vector2(0f, 1f);
			component.anchoredPosition = new Vector2(x, y);
			Toggle component2 = obj.GetComponent<Toggle>();
			QuietSelection(component2);
			((UnityEvent<bool>)(object)component2.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v)
			{
				onChanged(v);
			});
			AlignLeft(instance.CreateText(label, _panel.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x + 32f, y - 12f), instance.AveriaSerif, 16, instance.ValheimBeige, true, Color.black, 220f, 24f, false));
			return component2;
		}

		private void SyncCategoryToggles()
		{
			_dungeons.SetIsOnWithoutNotify(S.ShowDungeons.Value);
			_locations.SetIsOnWithoutNotify(S.ShowOtherLocations.Value);
			_buried.SetIsOnWithoutNotify(S.ShowBuried.Value);
			_explored.SetIsOnWithoutNotify(S.OnlyExploredAreas.Value);
			_discovered.SetIsOnWithoutNotify(S.OnlyDiscoveredItems.Value);
		}

		private void RebuildRows()
		{
			SyncCategoryToggles();
			foreach (Row row in _rows)
			{
				Object.Destroy((Object)(object)row.Root);
			}
			_rows.Clear();
			string filter = (((Object)(object)_filter != (Object)null) ? _filter.text.Trim() : string.Empty);
			Player player = Player.m_localPlayer;
			_builtDiscoveredOnly = S.OnlyDiscoveredItems.Value;
			bool discoveredOnly = _builtDiscoveredOnly && (Object)(object)player != (Object)null;
			foreach (CatalogEntry item in (from e in Catalog.Entries.Where((CatalogEntry e) => !discoveredOnly || player.IsKnownMaterial(e.Key)).ToList()
				where filter.Length == 0 || e.Name.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0
				orderby S.IsItemEnabled(e.Key) descending
				select e).ThenBy<CatalogEntry, string>((CatalogEntry e) => e.Name, StringComparer.CurrentCultureIgnoreCase).ToList())
			{
				_rows.Add(CreateRow(item));
			}
			UpdateSummary();
		}

		private void UpdateSummary()
		{
			Player localPlayer = Player.m_localPlayer;
			bool flag = S.OnlyDiscoveredItems.Value && (Object)(object)localPlayer != (Object)null;
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			foreach (CatalogEntry entry in Catalog.Entries)
			{
				num++;
				if (!flag || localPlayer.IsKnownMaterial(entry.Key))
				{
					num2++;
					if (S.IsItemEnabled(entry.Key))
					{
						num3++;
					}
				}
			}
			int num4 = num - num2;
			_summary.text = ((num4 > 0) ? $"{num3} of {num2} items pinned ({num4} undiscovered hidden). Right column = loaded nearby." : $"{num3} of {num2} items pinned. Right column = loaded nearby.");
		}

		private Row CreateRow(CatalogEntry entry)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Expected O, but got Unknown
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: 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_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			GUIManager instance = GUIManager.Instance;
			GameObject val = new GameObject("Row", new Type[3]
			{
				typeof(RectTransform),
				typeof(LayoutElement),
				typeof(HorizontalLayoutGroup)
			});
			val.transform.SetParent(_content, false);
			LayoutElement component = val.GetComponent<LayoutElement>();
			component.preferredHeight = 40f;
			component.minHeight = 40f;
			HorizontalLayoutGroup component2 = val.GetComponent<HorizontalLayoutGroup>();
			((LayoutGroup)component2).childAlignment = (TextAnchor)3;
			((HorizontalOrVerticalLayoutGroup)component2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)component2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)component2).spacing = 8f;
			((LayoutGroup)component2).padding = new RectOffset(6, 10, 0, 0);
			GameObject val2 = new GameObject("Icon", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(LayoutElement)
			});
			val2.transform.SetParent(val.transform, false);
			Fixed(val2, 32f, 32f);
			Image component3 = val2.GetComponent<Image>();
			component3.sprite = (((Object)(object)entry.Icon != (Object)null) ? entry.Icon : Icons.Generic);
			component3.preserveAspect = true;
			((Graphic)component3).raycastTarget = false;
			GameObject obj = instance.CreateText(entry.Name, val.transform, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), Vector2.zero, instance.AveriaSerif, 17, Color.white, true, Color.black, 100f, 40f, false);
			AlignLeft(obj, clip: true);
			LayoutElement obj2 = obj.AddComponent<LayoutElement>();
			obj2.flexibleWidth = 1f;
			obj2.minWidth = 60f;
			obj2.preferredHeight = 40f;
			string text = SourceLabel(entry.Sources);
			GameObject obj3 = instance.CreateText(text, val.transform, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), Vector2.zero, instance.AveriaSerif, 13, new Color(0.75f, 0.7f, 0.6f), false, Color.black, 80f, 40f, false);
			AlignLeft(obj3, clip: true);
			Fixed(obj3, 80f, 40f);
			GameObject obj4 = instance.CreateText("", val.transform, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), Vector2.zero, instance.AveriaSerifBold, 16, instance.ValheimOrange, true, Color.black, 56f, 40f, false);
			AlignLeft(obj4, clip: true);
			Fixed(obj4, 56f, 40f);
			Text component4 = obj4.GetComponent<Text>();
			component4.alignment = (TextAnchor)5;
			GameObject obj5 = instance.CreateToggle(val.transform, 26f, 26f);
			Fixed(obj5, 26f, 26f);
			Toggle component5 = obj5.GetComponent<Toggle>();
			QuietSelection(component5);
			component5.SetIsOnWithoutNotify(S.IsItemEnabled(entry.Key));
			((UnityEvent<bool>)(object)component5.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v)
			{
				S.SetItemEnabled(entry.Key, v);
			});
			return new Row
			{
				Entry = entry,
				Root = val,
				Toggle = component5,
				Nearby = component4
			};
		}

		private static void QuietSelection(Toggle toggle)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			ColorBlock colors = ((Selectable)toggle).colors;
			((ColorBlock)(ref colors)).fadeDuration = 0f;
			((Selectable)toggle).colors = colors;
			((UnityEvent<bool>)(object)toggle.onValueChanged).AddListener((UnityAction<bool>)delegate
			{
				EventSystem current = EventSystem.current;
				if ((Object)(object)current != (Object)null && (Object)(object)current.currentSelectedGameObject == (Object)(object)((Component)toggle).gameObject)
				{
					current.SetSelectedGameObject((GameObject)null);
				}
			});
		}

		private static string SourceLabel(PoiSource sources)
		{
			return sources switch
			{
				PoiSource.Deposit => "deposit", 
				PoiSource.Pickable => "pickable", 
				PoiSource.Breakable => "breakable", 
				PoiSource.None => string.Empty, 
				_ => "mixed", 
			};
		}

		private static void Fixed(GameObject go, float width, float height)
		{
			LayoutElement obj = go.GetComponent<LayoutElement>() ?? go.AddComponent<LayoutElement>();
			obj.preferredWidth = width;
			obj.minWidth = width;
			obj.preferredHeight = height;
			obj.minHeight = height;
			obj.flexibleWidth = 0f;
		}

		private static void AlignLeft(GameObject textGo, bool clip = false)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			Text component = textGo.GetComponent<Text>();
			if ((Object)(object)component != (Object)null)
			{
				component.alignment = (TextAnchor)3;
				component.horizontalOverflow = (HorizontalWrapMode)(!clip);
				component.verticalOverflow = (VerticalWrapMode)0;
			}
			textGo.GetComponent<RectTransform>().pivot = new Vector2(0f, 0.5f);
		}
	}
	internal sealed class PinManager : MonoBehaviour
	{
		private static readonly FieldRef<Minimap, List<PinData>> PinsRef = AccessTools.FieldRefAccess<Minimap, List<PinData>>("m_pins");

		private static readonly Func<Minimap, Vector3, bool> IsExplored = AccessTools.MethodDelegate<Func<Minimap, Vector3, bool>>(AccessTools.Method(typeof(Minimap), "IsExplored", new Type[1] { typeof(Vector3) }, (Type[])null), (object)null, true);

		private readonly HashSet<PinData> _livePins = new HashSet<PinData>();

		private readonly HashSet<string> _reported = new HashSet<string>();

		private float _nextRefresh;

		private bool _rebuildRequested;

		private LookoutPanel _ui;

		private static Settings S => Plugin.Settings;

		private void OnEnable()
		{
			S.Changed += RequestRebuild;
		}

		private void OnDisable()
		{
			S.Changed -= RequestRebuild;
			RemoveAllPins();
		}

		private void Update()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_ui == (Object)null)
			{
				_ui = ((Component)this).gameObject.AddComponent<LookoutPanel>();
			}
			KeyboardShortcut value = S.ToggleKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				_ui.Toggle();
			}
			if (!(Time.time < _nextRefresh))
			{
				_nextRefresh = Time.time + S.RefreshSeconds.Value;
				Refresh();
			}
		}

		private void Refresh()
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			Minimap instance = Minimap.instance;
			Player player = Player.m_localPlayer;
			if ((Object)(object)instance == (Object)null || (Object)(object)player == (Object)null)
			{
				foreach (PoiMarker item in PoiMarker.All)
				{
					item.Pin = null;
				}
				return;
			}
			Catalog.EnsureScanned();
			_ui.EnsureMapButton(instance);
			if (_rebuildRequested)
			{
				_rebuildRequested = false;
				RemoveAllPins();
			}
			_livePins.Clear();
			foreach (PinData item2 in PinsRef.Invoke(instance))
			{
				_livePins.Add(item2);
			}
			Vector3 position = ((Component)player).transform.position;
			float value = S.MaxDistance.Value;
			bool flag = S.OnlyExploredAreas.Value && IsExplored != null;
			bool flag2 = !S.ShowBuried.Value;
			bool value2 = S.ShowLabels.Value;
			bool value3 = S.LargeIcons.Value;
			bool discoveredOnly = S.OnlyDiscoveredItems.Value;
			Func<CatalogEntry, bool> allowed = (CatalogEntry e) => S.IsItemEnabled(e.Key) && (!discoveredOnly || player.IsKnownMaterial(e.Key));
			Catalog.ResetNearbyCounts();
			foreach (PoiMarker item3 in PoiMarker.All)
			{
				if (!item3.IsAttached)
				{
					continue;
				}
				bool isActive = item3.IsActive;
				if (isActive)
				{
					CatalogEntry[] items = item3.Items;
					for (int num = 0; num < items.Length; num++)
					{
						items[num].Nearby++;
					}
				}
				CatalogEntry catalogEntry = null;
				bool flag3;
				switch (item3.Category)
				{
				case PoiCategory.Dungeon:
					flag3 = S.ShowDungeons.Value;
					break;
				case PoiCategory.Location:
					flag3 = S.ShowOtherLocations.Value;
					break;
				default:
					catalogEntry = item3.FirstItem(allowed);
					flag3 = catalogEntry != null;
					break;
				}
				Vector3 position2 = ((Component)item3).transform.position;
				if (!(flag3 && isActive) || (!(value <= 0f) && !(Vector3.Distance(position, position2) <= value)) || (flag && !IsExplored(instance, position2)) || (flag2 && item3.Category == PoiCategory.Resource && item3.IsBuried))
				{
					RemovePin(item3);
				}
				else
				{
					if (item3.Pin != null && _livePins.Contains(item3.Pin))
					{
						continue;
					}
					string text = item3.HoverName ?? catalogEntry?.Name ?? string.Empty;
					Sprite val = item3.FixedIcon ?? catalogEntry?.Icon ?? Icons.Generic;
					if ((Object)(object)val == (Object)(object)Icons.Generic || string.IsNullOrEmpty(text))
					{
						string text2 = PoiPatches.CleanName(((Object)((Component)item3).gameObject).name);
						if (_reported.Add(text2))
						{
							string text3 = string.Join(", ", item3.Items.Select((CatalogEntry i) => i.Key + (((Object)(object)i.Icon == (Object)null) ? " (no icon)" : "")));
							Plugin.Log.LogDebug((object)$"Fallback pin for '{text2}' ({item3.Category}): hover='{item3.HoverName}', item='{catalogEntry?.Key}', yields=[{text3}]");
						}
					}
					PinData val2 = instance.AddPin(position2, (PinType)8, value2 ? text : string.Empty, false, false, 0L, default(PlatformUserID));
					val2.m_icon = val;
					val2.m_doubleSize = value3;
					item3.Pin = val2;
				}
			}
		}

		public static void RemovePin(PoiMarker marker)
		{
			if (marker.Pin != null)
			{
				Minimap instance = Minimap.instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.RemovePin(marker.Pin);
				}
				marker.Pin = null;
			}
		}

		private static void RemoveAllPins()
		{
			foreach (PoiMarker item in PoiMarker.All)
			{
				RemovePin(item);
			}
		}

		private void RequestRebuild()
		{
			_rebuildRequested = true;
			_nextRefresh = 0f;
		}
	}
	[BepInPlugin("dsoltyka.Lookout", "Lookout", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "dsoltyka.Lookout";

		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		internal static Settings Settings { get; private set; }

		private void Awake()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Settings = new Settings(((BaseUnityPlugin)this).Config);
			ConfigWatcher.Watch(((BaseUnityPlugin)this).Config, Log);
			_harmony = new Harmony("dsoltyka.Lookout");
			_harmony.PatchAll(typeof(PoiPatches));
			((Component)this).gameObject.AddComponent<PinManager>();
			Log.LogInfo((object)"Lookout 1.0.1 loaded");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal enum PoiCategory
	{
		Dungeon,
		Location,
		Resource
	}
	internal sealed class PoiMarker : MonoBehaviour
	{
		private static readonly HashSet<PoiMarker> s_all = new HashSet<PoiMarker>();

		public PinData Pin;

		private Func<bool> _isActive;

		private float? _topY;

		public static IReadOnlyCollection<PoiMarker> All => s_all;

		public PoiCategory Category { get; private set; }

		public string HoverName { get; private set; }

		public Sprite FixedIcon { get; private set; }

		public CatalogEntry[] Items { get; private set; } = Array.Empty<CatalogEntry>();

		public bool IsAttached { get; private set; }

		public bool IsActive
		{
			get
			{
				try
				{
					return _isActive == null || _isActive();
				}
				catch
				{
					return false;
				}
			}
		}

		public bool IsBuried
		{
			get
			{
				//IL_0099: 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_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				ZoneSystem instance = ZoneSystem.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return false;
				}
				if (!_topY.HasValue)
				{
					float num = ((Component)this).transform.position.y;
					Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren<Collider>();
					foreach (Collider val in componentsInChildren)
					{
						if ((Object)(object)val != (Object)null && val.enabled && !val.isTrigger)
						{
							float num2 = num;
							Bounds bounds = val.bounds;
							num = Mathf.Max(num2, ((Bounds)(ref bounds)).max.y);
						}
					}
					_topY = num;
				}
				float num3 = default(float);
				if (instance.GetGroundHeight(((Component)this).transform.position, ref num3))
				{
					return _topY.Value < num3 - 0.25f;
				}
				return false;
			}
		}

		public static PoiMarker AttachFixed(GameObject target, PoiCategory category, string label, Sprite icon)
		{
			PoiMarker poiMarker = Get(target);
			poiMarker.Category = category;
			poiMarker.HoverName = label;
			poiMarker.FixedIcon = icon;
			poiMarker.Items = Array.Empty<CatalogEntry>();
			poiMarker._isActive = null;
			poiMarker.IsAttached = true;
			return poiMarker;
		}

		public static PoiMarker AttachResource(GameObject target, string hoverName, CatalogEntry[] items, Func<bool> isActive)
		{
			PoiMarker poiMarker = Get(target);
			poiMarker.Category = PoiCategory.Resource;
			poiMarker.HoverName = hoverName;
			poiMarker.FixedIcon = null;
			poiMarker.Items = items ?? Array.Empty<CatalogEntry>();
			poiMarker._isActive = isActive;
			poiMarker.IsAttached = true;
			return poiMarker;
		}

		public CatalogEntry FirstItem(Func<CatalogEntry, bool> allowed)
		{
			CatalogEntry[] items = Items;
			foreach (CatalogEntry catalogEntry in items)
			{
				if (allowed(catalogEntry))
				{
					return catalogEntry;
				}
			}
			return null;
		}

		private static PoiMarker Get(GameObject target)
		{
			PoiMarker component = target.GetComponent<PoiMarker>();
			if (!((Object)(object)component != (Object)null))
			{
				return target.AddComponent<PoiMarker>();
			}
			return component;
		}

		private void OnEnable()
		{
			s_all.Add(this);
		}

		private void OnDisable()
		{
			s_all.Remove(this);
			PinManager.RemovePin(this);
		}
	}
	[HarmonyPatch]
	internal static class PoiPatches
	{
		private const float OverworldMaxY = 3000f;

		private static readonly List<ResourceRules.Yield> s_scratch = new List<ResourceRules.Yield>();

		[HarmonyPatch(typeof(Location), "Awake")]
		[HarmonyPostfix]
		private static void Location_Awake(Location __instance)
		{
			Guard(delegate
			{
				TagLocation(__instance);
			});
		}

		private static void TagLocation(Location location)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!(((Component)location).transform.position.y > 3000f))
			{
				string prefabName = CleanName(((Object)((Component)location).gameObject).name);
				if (location.m_hasInterior)
				{
					PoiMarker.AttachFixed(((Component)location).gameObject, PoiCategory.Dungeon, LocationNames.Get(prefabName), Icons.Dungeon);
				}
				else
				{
					PoiMarker.AttachFixed(((Component)location).gameObject, PoiCategory.Location, LocationNames.Get(prefabName), Icons.Location);
				}
			}
		}

		[HarmonyPatch(typeof(Destructible), "Awake")]
		[HarmonyPostfix]
		private static void Destructible_Awake(Destructible __instance)
		{
			Guard(delegate
			{
				TagResource(((Component)__instance).gameObject, null);
			});
		}

		[HarmonyPatch(typeof(MineRock), "Start")]
		[HarmonyPostfix]
		private static void MineRock_Start(MineRock __instance)
		{
			Guard(delegate
			{
				TagResource(((Component)__instance).gameObject, null);
			});
		}

		[HarmonyPatch(typeof(MineRock5), "Awake")]
		[HarmonyPostfix]
		private static void MineRock5_Awake(MineRock5 __instance)
		{
			Guard(delegate
			{
				TagResource(((Component)__instance).gameObject, null);
			});
		}

		[HarmonyPatch(typeof(Pickable), "Awake")]
		[HarmonyPostfix]
		private static void Pickable_Awake(Pickable __instance)
		{
			Guard(delegate
			{
				TagResource(((Component)__instance).gameObject, () => !__instance.GetPicked());
			});
		}

		private static void TagResource(GameObject go, Func<bool> isActive)
		{
			if (!HasValidZdo(go))
			{
				return;
			}
			PoiMarker component = go.GetComponent<PoiMarker>();
			if ((Object)(object)component != (Object)null && component.IsAttached)
			{
				return;
			}
			s_scratch.Clear();
			string text = ResourceRules.Collect(go, s_scratch);
			if (s_scratch.Count != 0)
			{
				CatalogEntry[] array = new CatalogEntry[s_scratch.Count];
				for (int i = 0; i < s_scratch.Count; i++)
				{
					array[i] = Catalog.Register(s_scratch[i].Item, s_scratch[i].Source);
				}
				string hoverName = ((!string.IsNullOrEmpty(text)) ? Catalog.Localize(text) : null);
				PoiMarker.AttachResource(go, hoverName, array, isActive);
			}
		}

		private static void Guard(Action action)
		{
			try
			{
				action();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"POI tagging failed: {arg}");
			}
		}

		private static bool HasValidZdo(GameObject go)
		{
			ZNetView component = go.GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null)
			{
				return component.IsValid();
			}
			return false;
		}

		internal static string CleanName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return string.Empty;
			}
			int num = name.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num < 0)
			{
				return name;
			}
			return name.Substring(0, num);
		}
	}
	internal static class LocationNames
	{
		private static readonly Dictionary<string, string> Known = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Crypt2", "Burial Chambers" },
			{ "Crypt3", "Burial Chambers" },
			{ "Crypt4", "Burial Chambers" },
			{ "TrollCave02", "Troll Cave" },
			{ "SunkenCrypt4", "Sunken Crypt" },
			{ "MountainCave02", "Frost Cave" },
			{ "Mistlands_DvergrBossEntrance1", "Infested Mine" },
			{ "Hildir_crypt", "Smouldering Tomb" },
			{ "Hildir_cave", "Howling Cavern" },
			{ "Hildir_plainsfortress", "Sealed Tower" },
			{ "Vendor_BlackForest", "Haldor" },
			{ "Hildir_camp", "Hildir" },
			{ "BogWitch_Camp", "Bog Witch" },
			{ "Eikthyrnir", "Eikthyr Altar" },
			{ "GDKing", "The Elder Altar" },
			{ "Bonemass", "Bonemass Altar" },
			{ "Dragonqueen", "Moder Altar" },
			{ "GoblinKing", "Yagluth Altar" },
			{ "Mistlands_DvergrBossEntrance2", "The Queen's Lair" },
			{ "GoblinCamp2", "Fuling Village" },
			{ "TarPit1", "Tar Pit" },
			{ "TarPit2", "Tar Pit" },
			{ "TarPit3", "Tar Pit" }
		};

		private static readonly Regex TrailingDigits = new Regex("\\d+$", RegexOptions.Compiled);

		private static readonly Regex CamelBoundary = new Regex("(?<=[a-z])(?=[A-Z])", RegexOptions.Compiled);

		public static string Get(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return string.Empty;
			}
			if (Known.TryGetValue(prefabName, out var value))
			{
				return value;
			}
			string input = TrailingDigits.Replace(prefabName, string.Empty).Replace('_', ' ').Trim();
			input = CamelBoundary.Replace(input, " ");
			StringBuilder stringBuilder = new StringBuilder(input.Length);
			bool flag = true;
			string text = input;
			foreach (char c in text)
			{
				if (c == ' ')
				{
					if (stringBuilder.Length > 0 && stringBuilder[stringBuilder.Length - 1] != ' ')
					{
						stringBuilder.Append(' ');
					}
					flag = true;
				}
				else
				{
					stringBuilder.Append(flag ? char.ToUpperInvariant(c) : c);
					flag = false;
				}
			}
			return stringBuilder.ToString().Trim();
		}
	}
	internal sealed class Settings
	{
		public const string DefaultItems = "";

		private readonly HashSet<string> _enabled = new HashSet<string>(StringComparer.Ordinal);

		private string _parsedFrom;

		public ConfigEntry<bool> ShowDungeons { get; }

		public ConfigEntry<bool> ShowOtherLocations { get; }

		public ConfigEntry<string> EnabledItems { get; }

		public ConfigEntry<bool> OnlyDiscoveredItems { get; }

		public ConfigEntry<float> MaxDistance { get; }

		public ConfigEntry<bool> ShowBuried { get; }

		public ConfigEntry<bool> OnlyExploredAreas { get; }

		public ConfigEntry<bool> ShowLabels { get; }

		public ConfigEntry<bool> LargeIcons { get; }

		public ConfigEntry<float> RefreshSeconds { get; }

		public ConfigEntry<KeyboardShortcut> ToggleKey { get; }

		public ConfigEntry<bool> MapButton { get; }

		public event Action Changed;

		public Settings(ConfigFile config)
		{
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Expected O, but got Unknown
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			ShowDungeons = config.Bind<bool>("1 - What to pin", "Dungeons", true, "Pin dungeon entrances: burial chambers, troll caves, sunken crypts, frost caves, infested mines and any other location with an interior.");
			ShowOtherLocations = config.Bind<bool>("1 - What to pin", "OtherLocations", false, "Pin surface locations without an interior: ruins, abandoned camps, tar pits, runestones, altars, villages.");
			EnabledItems = config.Bind<string>("1 - What to pin", "Items", "", "Comma-separated item tokens to pin, e.g. $item_copperore,$item_tinore. Any deposit, breakable or pickable that yields one of these gets a pin with that item's icon. Empty by default: nothing is pinned until you opt in. Easiest to edit from the in-game panel (see Interface), which lists every item the world can yield.");
			OnlyDiscoveredItems = config.Bind<bool>("1 - What to pin", "OnlyDiscoveredItems", true, "Only list and pin items your character has already discovered (picked up at least once). Keeps the panel from spoiling items you have not found yet. Turn off to see everything the world can yield.");
			MaxDistance = config.Bind<float>("2 - Display", "MaxDistance", 0f, new ConfigDescription("Only pin objects within this many meters of the player. 0 means everything the game has loaded around you (roughly 200 m).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), Array.Empty<object>()));
			ShowBuried = config.Bind<bool>("2 - Display", "ShowBuried", false, "Also pin deposits that are completely below the terrain surface, such as untouched silver veins. Off by default so the radar does not give away hidden ore; partially exposed veins are always shown.");
			OnlyExploredAreas = config.Bind<bool>("2 - Display", "OnlyExploredAreas", false, "Only pin objects that sit on a part of the map you have already explored (including map data shared with you). Off by default so pins always appear; turn on if you do not want the radar to hint at unexplored terrain.");
			ShowLabels = config.Bind<bool>("2 - Display", "ShowLabels", true, "Draw the name next to each pin (for example 'Copper deposit' or 'Burial Chambers').");
			LargeIcons = config.Bind<bool>("2 - Display", "LargeIcons", false, "Draw the pins at double size.");
			RefreshSeconds = config.Bind<float>("2 - Display", "RefreshSeconds", 0.5f, new ConfigDescription("How often pins are re-evaluated (distance, picked state, new objects).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			ToggleKey = config.Bind<KeyboardShortcut>("3 - Interface", "ToggleKey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Key that opens and closes the Lookout panel.");
			MapButton = config.Bind<bool>("3 - Interface", "MapButton", true, "Show a 'Lookout' button in the corner of the large map that opens the panel.");
			config.SettingChanged += delegate
			{
				this.Changed?.Invoke();
			};
		}

		public bool IsItemEnabled(string key)
		{
			EnsureParsed();
			return _enabled.Contains(key);
		}

		public void SetItemEnabled(string key, bool enabled)
		{
			EnsureParsed();
			if (enabled ? _enabled.Add(key) : _enabled.Remove(key))
			{
				List<string> list = new List<string>(_enabled);
				list.Sort(StringComparer.Ordinal);
				string value = (_parsedFrom = string.Join(",", list));
				EnabledItems.Value = value;
			}
		}

		private void EnsureParsed()
		{
			string text = EnabledItems.Value ?? string.Empty;
			if ((object)text == _parsedFrom || text == _parsedFrom)
			{
				return;
			}
			_enabled.Clear();
			string[] array = text.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length > 0)
				{
					_enabled.Add(text2);
				}
			}
			_parsedFrom = text;
		}
	}
	internal static class BuildInfo
	{
		public const string Name = "Lookout";

		public const string Version = "1.0.1";
	}
}