Decompiled source of UnlockChecklist v0.1.1

UnlockChecklist.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HG.Reflection;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RoR2;
using RoR2.Skills;
using RoR2.UI;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("UnlockChecklist")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("UnlockChecklist")]
[assembly: AssemblyTitle("UnlockChecklist")]
[assembly: AssemblyVersion("0.1.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 UnlockChecklist
{
	internal static class ChecklistStore
	{
		private static readonly List<string> order = new List<string>();

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

		private static bool loaded;

		public static IReadOnlyList<string> Tags => order;

		public static int Count => order.Count;

		private static string FilePath => Path.Combine(Paths.ConfigPath, "com.bdub.UnlockChecklist.tags.txt");

		public static event Action onChanged;

		public static bool IsTagged(string unlockableName)
		{
			if (!string.IsNullOrEmpty(unlockableName))
			{
				return tagged.Contains(unlockableName);
			}
			return false;
		}

		public static bool Toggle(string unlockableName)
		{
			if (string.IsNullOrEmpty(unlockableName))
			{
				return false;
			}
			if (tagged.Remove(unlockableName))
			{
				order.Remove(unlockableName);
				Changed();
				return false;
			}
			tagged.Add(unlockableName);
			order.Add(unlockableName);
			Changed();
			return true;
		}

		public static bool Add(string unlockableName)
		{
			if (string.IsNullOrEmpty(unlockableName) || !tagged.Add(unlockableName))
			{
				return false;
			}
			order.Add(unlockableName);
			Changed();
			return true;
		}

		public static bool Remove(string unlockableName)
		{
			if (string.IsNullOrEmpty(unlockableName) || !tagged.Remove(unlockableName))
			{
				return false;
			}
			order.Remove(unlockableName);
			Changed();
			return true;
		}

		public static int ClearCompleted()
		{
			int num = 0;
			for (int num2 = order.Count - 1; num2 >= 0; num2--)
			{
				if (UnlockIndex.IsUnlocked(order[num2]))
				{
					tagged.Remove(order[num2]);
					order.RemoveAt(num2);
					num++;
				}
			}
			if (num > 0)
			{
				Changed();
			}
			return num;
		}

		public static int Clear()
		{
			int count = order.Count;
			if (count == 0)
			{
				return 0;
			}
			order.Clear();
			tagged.Clear();
			Changed();
			return count;
		}

		public static void Load()
		{
			order.Clear();
			tagged.Clear();
			try
			{
				if (File.Exists(FilePath))
				{
					string[] array = File.ReadAllLines(FilePath);
					for (int i = 0; i < array.Length; i++)
					{
						string text = array[i].Trim();
						if (text.Length != 0 && text[0] != '#' && tagged.Add(text))
						{
							order.Add(text);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not read " + FilePath + ": " + ex.Message));
			}
			loaded = true;
			ChecklistStore.onChanged?.Invoke();
		}

		private static void Changed()
		{
			Save();
			ChecklistStore.onChanged?.Invoke();
		}

		private static void Save()
		{
			if (!loaded)
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# UnlockChecklist tags - one UnlockableDef name per line, in list order.");
			stringBuilder.AppendLine("# Safe to edit by hand; lines starting with # are ignored.");
			stringBuilder.AppendLine("# Names that do not resolve are kept and shown as unresolved, not dropped.");
			foreach (string item in order)
			{
				stringBuilder.AppendLine(item);
			}
			try
			{
				File.WriteAllText(FilePath, stringBuilder.ToString());
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not write " + FilePath + ": " + ex.Message));
			}
		}
	}
	public class ChecklistUI : MonoBehaviour
	{
		private struct RowEntry
		{
			public string unlockableName;

			public TextMeshProUGUI title;

			public TextMeshProUGUI requirement;

			public Image badge;

			public TextMeshProUGUI badgeLabel;

			public bool wasUnlocked;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Close;
		}

		private static ChecklistUI instance;

		private RectTransform window;

		private RectTransform content;

		private LayoutElement listAreaElement;

		private TextMeshProUGUI titleText;

		private TextMeshProUGUI statusText;

		private readonly List<RowEntry> rows = new List<RowEntry>();

		private float nextStateCheck;

		private const float WindowWidth = 1020f;

		private const float MaxWindowHeight = 1000f;

		private const int WindowPadding = 24;

		private const int ListPadding = 8;

		private const float RowSpacing = 6f;

		private const float RowHeight = 76f;

		private const int MaxRows = 8;

		private const float IconSize = 56f;

		private const float StateCheckInterval = 1f;

		private const float Chrome = 196f;

		private static readonly Color WindowColor = new Color(0.07f, 0.08f, 0.1f, 0.97f);

		private static readonly Color PanelColor = new Color(0.12f, 0.13f, 0.16f, 0.9f);

		private static readonly Color RowColor = new Color(0.16f, 0.17f, 0.21f, 0.85f);

		private static readonly Color ButtonIdle = new Color(0.18f, 0.19f, 0.23f, 1f);

		private static readonly Color ButtonActive = new Color(0.9f, 0.58f, 0.16f, 1f);

		private static readonly Color DoneColor = new Color(0.38f, 0.8f, 0.42f, 1f);

		private static readonly Color TextColor = new Color(0.9f, 0.91f, 0.94f, 1f);

		private static readonly Color DimTextColor = new Color(0.55f, 0.56f, 0.6f, 1f);

		public static bool IsOpen => (Object)(object)instance != (Object)null;

		public static void Toggle()
		{
			if (IsOpen)
			{
				Close();
			}
			else
			{
				Open();
			}
		}

		public static void Open()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			Close();
			GameObject val = new GameObject("UnlockChecklistUI");
			val.SetActive(false);
			Canvas obj = val.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 520;
			CanvasScaler obj2 = val.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.screenMatchMode = (ScreenMatchMode)0;
			obj2.matchWidthOrHeight = 0.5f;
			val.AddComponent<GraphicRaycaster>();
			MPEventSystemProvider val2 = val.AddComponent<MPEventSystemProvider>();
			val2.fallBackToMainEventSystem = true;
			val.AddComponent<MPEventSystemLocator>();
			LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
			MPEventSystem val3 = ((firstLocalUser != null) ? firstLocalUser.eventSystem : null);
			CursorOpener val4 = (Object.op_Implicit((Object)(object)Run.instance) ? val.AddComponent<CursorOpener>() : null);
			ChecklistUI checklistUI = val.AddComponent<ChecklistUI>();
			checklistUI.Build(val);
			instance = checklistUI;
			val.SetActive(true);
			if (Object.op_Implicit((Object)(object)val4))
			{
				val4.forceCursorForGamePad = true;
			}
			if (Object.op_Implicit((Object)(object)val3))
			{
				val2.eventSystem = val3;
			}
		}

		public static void Close()
		{
			if (Object.op_Implicit((Object)(object)instance))
			{
				Object.Destroy((Object)(object)((Component)instance).gameObject);
			}
			instance = null;
		}

		private void OnEnable()
		{
			ChecklistStore.onChanged += OnStoreChanged;
		}

		private void OnDisable()
		{
			ChecklistStore.onChanged -= OnStoreChanged;
		}

		private void OnDestroy()
		{
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}

		private void OnStoreChanged()
		{
			RebuildRows();
		}

		private void Build(GameObject root)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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_01b9: Unknown result type (might be due to invalid IL or missing references)
			CreateStretched("Backdrop", root.transform, new Color(0f, 0f, 0f, 0.72f));
			window = CreatePanel("Window", root.transform, WindowColor);
			window.anchorMin = new Vector2(0.5f, 0.5f);
			window.anchorMax = new Vector2(0.5f, 0.5f);
			window.pivot = new Vector2(0.5f, 0.5f);
			window.anchoredPosition = Vector2.zero;
			window.sizeDelta = new Vector2(1020f, 600f);
			VerticalLayoutGroup obj = ((Component)window).gameObject.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj).padding = new RectOffset(24, 24, 20, 20);
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 10f;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			titleText = CreateLabel("Title", window, "UNLOCK CHECKLIST", 34f, (FontStyles)1, 46f);
			content = CreateScrollArea(window, "ListArea", out listAreaElement);
			VerticalLayoutGroup obj2 = ((Component)content).gameObject.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj2).padding = new RectOffset(8, 8, 8, 8);
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 6f;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			statusText = CreateLabel("Status", window, HintLine(), 18f, (FontStyles)2, 28f);
			((Graphic)statusText).color = DimTextColor;
			CreateButtonRow(window);
			RebuildRows();
		}

		private static string HintLine()
		{
			bool value = Plugin.TagOnLeftClickWhenLocked.Value;
			bool value2 = Plugin.TagOnRightClick.Value;
			string text = ((value && value2) ? "left-click a locked entry, or right-click any entry" : (value ? "left-click a locked entry" : "right-click an entry"));
			return "In the character select loadout panel, " + text + " to add it here.";
		}

		private RectTransform CreateScrollArea(RectTransform parent, string name, out LayoutElement heightElement)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = CreateChildRect(name, (Transform)(object)parent);
			heightElement = AddFixedHeight(val, 200f);
			ScrollRect obj = ((Component)val).gameObject.AddComponent<ScrollRect>();
			obj.horizontal = false;
			obj.vertical = true;
			obj.movementType = (MovementType)2;
			obj.scrollSensitivity = 30f;
			RectTransform val2 = CreatePanel("Viewport", (Transform)(object)val, PanelColor);
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			val2.offsetMin = Vector2.zero;
			val2.offsetMax = Vector2.zero;
			((Component)val2).gameObject.AddComponent<RectMask2D>();
			obj.viewport = val2;
			RectTransform val3 = CreateChildRect("Content", (Transform)(object)val2);
			val3.anchorMin = new Vector2(0f, 1f);
			val3.anchorMax = new Vector2(1f, 1f);
			val3.pivot = new Vector2(0.5f, 1f);
			val3.sizeDelta = Vector2.zero;
			val3.anchoredPosition = Vector2.zero;
			obj.content = val3;
			((Component)val3).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			return val3;
		}

		private void CreateButtonRow(RectTransform parent)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			RectTransform obj = CreateChildRect("Buttons", (Transform)(object)parent);
			AddFixedHeight(obj, 52f);
			HorizontalLayoutGroup obj2 = ((Component)obj).gameObject.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 12f;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = true;
			CreateActionButton(obj, "Clear completed", ButtonIdle, new UnityAction(OnClearCompleted));
			Color buttonActive = ButtonActive;
			object obj3 = <>O.<0>__Close;
			if (obj3 == null)
			{
				UnityAction val = Close;
				<>O.<0>__Close = val;
				obj3 = (object)val;
			}
			CreateActionButton(obj, "Close", buttonActive, (UnityAction)obj3);
		}

		private void RebuildRows()
		{
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			rows.Clear();
			DestroyChildren(content);
			List<UnlockEntry> list = new List<UnlockEntry>();
			List<UnlockEntry> list2 = new List<UnlockEntry>();
			foreach (string tag in ChecklistStore.Tags)
			{
				UnlockEntry entry = UnlockIndex.GetEntry(tag);
				if (entry.unlocked)
				{
					list2.Add(entry);
				}
				else
				{
					list.Add(entry);
				}
			}
			foreach (UnlockEntry item in list)
			{
				CreateRow(item);
			}
			if (Plugin.ShowCompleted.Value)
			{
				foreach (UnlockEntry item2 in list2)
				{
					CreateRow(item2);
				}
			}
			if (((Transform)content).childCount == 0)
			{
				RectTransform obj = CreateChildRect("EmptyNote", (Transform)(object)content);
				AddFixedHeight(obj, 56f);
				((Graphic)CreateLabelIn(obj, (ChecklistStore.Count == 0) ? "Nothing tagged yet." : "Everything you tagged is unlocked. Press Clear completed to empty the list.", 19f, (FontStyles)2)).color = DimTextColor;
			}
			if (Object.op_Implicit((Object)(object)titleText))
			{
				((TMP_Text)titleText).text = ((list2.Count > 0) ? ("UNLOCK CHECKLIST    " + list.Count + " to go, " + list2.Count + " done") : ("UNLOCK CHECKLIST    " + list.Count + " to go"));
			}
			ApplyLayout();
		}

		private void CreateRow(UnlockEntry entry)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: 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_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: 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_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = CreatePanel("Row_" + entry.unlockableName, (Transform)(object)content, RowColor);
			AddFixedHeight(val, 76f);
			if (Object.op_Implicit((Object)(object)entry.icon))
			{
				RectTransform obj = CreateChildRect("Icon", (Transform)(object)val);
				obj.anchorMin = new Vector2(0f, 0.5f);
				obj.anchorMax = new Vector2(0f, 0.5f);
				obj.pivot = new Vector2(0f, 0.5f);
				obj.sizeDelta = new Vector2(56f, 56f);
				obj.anchoredPosition = new Vector2(12f, 0f);
				Image obj2 = ((Component)obj).gameObject.AddComponent<Image>();
				obj2.sprite = entry.icon;
				obj2.preserveAspect = true;
				((Graphic)obj2).raycastTarget = false;
				((Graphic)obj2).color = (Color)(entry.unlocked ? Color.white : new Color(1f, 1f, 1f, 0.6f));
			}
			RectTransform obj3 = CreateChildRect("Title", (Transform)(object)val);
			obj3.anchorMin = new Vector2(0f, 0.5f);
			obj3.anchorMax = new Vector2(1f, 1f);
			obj3.offsetMin = new Vector2(80f, 0f);
			obj3.offsetMax = new Vector2(-190f, -8f);
			TextMeshProUGUI val2 = ConfigureText(obj3, entry.Title, 21f, (FontStyles)1);
			((TMP_Text)val2).alignment = (TextAlignmentOptions)1025;
			((TMP_Text)val2).enableAutoSizing = true;
			((TMP_Text)val2).fontSizeMin = 15f;
			((TMP_Text)val2).fontSizeMax = 21f;
			RectTransform obj4 = CreateChildRect("Requirement", (Transform)(object)val);
			obj4.anchorMin = new Vector2(0f, 0f);
			obj4.anchorMax = new Vector2(1f, 0.5f);
			obj4.offsetMin = new Vector2(80f, 8f);
			obj4.offsetMax = new Vector2(-190f, 0f);
			TextMeshProUGUI val3 = ConfigureText(obj4, entry.requirement, 17f, (FontStyles)0);
			((TMP_Text)val3).alignment = (TextAlignmentOptions)257;
			((Graphic)val3).color = DimTextColor;
			RectTransform val4 = CreatePanel("Badge", (Transform)(object)val, DoneColor);
			val4.anchorMin = new Vector2(1f, 0.5f);
			val4.anchorMax = new Vector2(1f, 0.5f);
			val4.pivot = new Vector2(1f, 0.5f);
			val4.sizeDelta = new Vector2(92f, 30f);
			val4.anchoredPosition = new Vector2(-62f, 0f);
			TextMeshProUGUI val5 = CreateLabelIn(val4, "DONE", 16f, (FontStyles)1);
			((Graphic)val5).color = new Color(0.05f, 0.09f, 0.06f, 1f);
			RectTransform val6 = CreatePanel("Remove", (Transform)(object)val, ButtonIdle);
			val6.anchorMin = new Vector2(1f, 0.5f);
			val6.anchorMax = new Vector2(1f, 0.5f);
			val6.pivot = new Vector2(1f, 0.5f);
			val6.sizeDelta = new Vector2(40f, 40f);
			val6.anchoredPosition = new Vector2(-10f, 0f);
			Button obj5 = ((Component)val6).gameObject.AddComponent<Button>();
			((Selectable)obj5).targetGraphic = (Graphic)(object)((Component)val6).GetComponent<Image>();
			CreateLabelIn(val6, "x", 22f, (FontStyles)1);
			string captured = entry.unlockableName;
			((UnityEvent)obj5.onClick).AddListener((UnityAction)delegate
			{
				ChecklistStore.Remove(captured);
			});
			RowEntry rowEntry = new RowEntry
			{
				unlockableName = entry.unlockableName,
				title = val2,
				requirement = val3,
				badge = ((Component)val4).GetComponent<Image>(),
				badgeLabel = val5,
				wasUnlocked = entry.unlocked
			};
			rows.Add(rowEntry);
			ApplyRowState(rowEntry, entry.unlocked);
		}

		private static void ApplyRowState(RowEntry row, bool unlocked)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)row.badge))
			{
				((Component)row.badge).gameObject.SetActive(unlocked);
			}
			if (Object.op_Implicit((Object)(object)row.title))
			{
				((Graphic)row.title).color = (unlocked ? DimTextColor : TextColor);
				((TMP_Text)row.title).fontStyle = (FontStyles)((!unlocked) ? 1 : 65);
			}
		}

		private void ApplyLayout()
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Clamp((!Object.op_Implicit((Object)(object)content)) ? 1 : ((Transform)content).childCount, 1, 8);
			while (num > 1 && 196f + ListHeight(num) > 1000f)
			{
				num--;
			}
			float num2 = ListHeight(num);
			if (Object.op_Implicit((Object)(object)listAreaElement))
			{
				listAreaElement.preferredHeight = num2;
				listAreaElement.minHeight = num2;
			}
			if (Object.op_Implicit((Object)(object)window))
			{
				window.sizeDelta = new Vector2(1020f, 196f + num2);
			}
		}

		private static float ListHeight(int rowCount)
		{
			return 16f + (float)rowCount * 76f + (float)(rowCount - 1) * 6f;
		}

		private void OnClearCompleted()
		{
			int num = ChecklistStore.ClearCompleted();
			SetStatus((num == 0) ? "Nothing on the list is unlocked yet." : ("Cleared " + num + " completed " + ((num == 1) ? "entry." : "entries.")));
		}

		private void SetStatus(string message)
		{
			if (Object.op_Implicit((Object)(object)statusText))
			{
				((TMP_Text)statusText).text = message;
			}
		}

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)27))
			{
				Close();
			}
			else if (!(Time.unscaledTime < nextStateCheck))
			{
				nextStateCheck = Time.unscaledTime + 1f;
				RefreshUnlockState();
			}
		}

		private void RefreshUnlockState()
		{
			bool flag = false;
			for (int i = 0; i < rows.Count; i++)
			{
				RowEntry rowEntry = rows[i];
				bool flag2 = UnlockIndex.IsUnlocked(rowEntry.unlockableName);
				if (flag2 != rowEntry.wasUnlocked)
				{
					if (flag2 && !Plugin.ShowCompleted.Value)
					{
						flag = true;
						break;
					}
					rowEntry.wasUnlocked = flag2;
					rows[i] = rowEntry;
					ApplyRowState(rowEntry, flag2);
				}
			}
			if (flag)
			{
				RebuildRows();
			}
		}

		private static void DestroyChildren(RectTransform parent)
		{
			if (Object.op_Implicit((Object)(object)parent))
			{
				for (int num = ((Transform)parent).childCount - 1; num >= 0; num--)
				{
					Object.Destroy((Object)(object)((Component)((Transform)parent).GetChild(num)).gameObject);
				}
			}
		}

		private static RectTransform CreateChildRect(string name, Transform parent)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }).transform;
			((Transform)val).SetParent(parent, false);
			val.sizeDelta = Vector2.zero;
			return val;
		}

		private static RectTransform CreatePanel(string name, Transform parent, Color color)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			RectTransform obj = CreateChildRect(name, parent);
			((Graphic)((Component)obj).gameObject.AddComponent<Image>()).color = color;
			return obj;
		}

		private static void CreateStretched(string name, Transform parent, Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			RectTransform obj = CreatePanel(name, parent, color);
			obj.anchorMin = Vector2.zero;
			obj.anchorMax = Vector2.one;
			obj.offsetMin = Vector2.zero;
			obj.offsetMax = Vector2.zero;
		}

		private static LayoutElement AddFixedHeight(RectTransform rect, float height)
		{
			LayoutElement obj = ((Component)rect).gameObject.AddComponent<LayoutElement>();
			obj.preferredHeight = height;
			obj.minHeight = height;
			return obj;
		}

		private static TextMeshProUGUI CreateLabel(string name, RectTransform parent, string text, float size, FontStyles style, float height)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			RectTransform rect = CreateChildRect(name, (Transform)(object)parent);
			AddFixedHeight(rect, height);
			return ConfigureText(rect, text, size, style);
		}

		private static TextMeshProUGUI CreateLabelIn(RectTransform parent, string text, float size, FontStyles style)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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)
			RectTransform obj = CreateChildRect("Label", (Transform)(object)parent);
			obj.anchorMin = Vector2.zero;
			obj.anchorMax = Vector2.one;
			obj.offsetMin = new Vector2(6f, 2f);
			obj.offsetMax = new Vector2(-6f, -2f);
			return ConfigureText(obj, text, size, style);
		}

		private static TextMeshProUGUI ConfigureText(RectTransform rect, string text, float size, FontStyles style)
		{
			//IL_001a: 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)
			TextMeshProUGUI obj = ((Component)rect).gameObject.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).text = text;
			((TMP_Text)obj).fontSize = size;
			((TMP_Text)obj).fontStyle = style;
			((Graphic)obj).color = TextColor;
			((TMP_Text)obj).alignment = (TextAlignmentOptions)514;
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).enableWordWrapping = false;
			((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
			return obj;
		}

		private static void CreateActionButton(RectTransform parent, string text, Color color, UnityAction onClick)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = CreatePanel("Button_" + text, (Transform)(object)parent, color);
			Button obj = ((Component)val).gameObject.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)((Component)val).GetComponent<Image>();
			((UnityEvent)obj.onClick).AddListener(onClick);
			CreateLabelIn(val, text, 22f, (FontStyles)1);
		}
	}
	internal static class Commands
	{
		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCUI(ConCommandArgs args)
		{
			ChecklistUI.Toggle();
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCList(ConCommandArgs args)
		{
			if (ChecklistStore.Count == 0)
			{
				Print("Checklist is empty. Tag something in the character select, or use uc_tag <name>.");
				return;
			}
			StringBuilder stringBuilder = new StringBuilder($"{ChecklistStore.Count} tagged:\n");
			foreach (string tag in ChecklistStore.Tags)
			{
				UnlockEntry entry = UnlockIndex.GetEntry(tag);
				stringBuilder.AppendLine("  [" + (entry.unlocked ? "x" : " ") + "] " + entry.Title);
				stringBuilder.AppendLine("        " + Strip(entry.requirement));
				stringBuilder.AppendLine("        " + tag);
			}
			Print(stringBuilder.ToString());
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCTag(ConCommandArgs args)
		{
			string name;
			if (((ConCommandArgs)(ref args)).Count < 1)
			{
				Print("Usage: uc_tag <unlockable name or search>   (see uc_find)");
			}
			else if (ResolveOne(((ConCommandArgs)(ref args)).GetArgString(0), out name))
			{
				UnlockEntry entry = UnlockIndex.GetEntry(name);
				Print(ChecklistStore.Add(name) ? ("Tagged " + entry.Title + ".") : (entry.Title + " is already on the checklist."));
			}
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCUntag(ConCommandArgs args)
		{
			if (((ConCommandArgs)(ref args)).Count < 1)
			{
				Print("Usage: uc_untag <unlockable name or search>   (see uc_list)");
				return;
			}
			string argString = ((ConCommandArgs)(ref args)).GetArgString(0);
			List<string> list = new List<string>();
			foreach (string tag in ChecklistStore.Tags)
			{
				UnlockEntry entry = UnlockIndex.GetEntry(tag);
				if (Matches(tag, argString) || Matches(entry.Title, argString))
				{
					list.Add(tag);
				}
			}
			if (list.Count == 0)
			{
				Print("Nothing on the checklist matches '" + argString + "'. Try uc_list.");
				return;
			}
			if (list.Count > 1)
			{
				PrintCandidates(argString, list);
				return;
			}
			UnlockEntry entry2 = UnlockIndex.GetEntry(list[0]);
			ChecklistStore.Remove(list[0]);
			Print("Untagged " + entry2.Title + ".");
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCClear(ConCommandArgs args)
		{
			string text = ((((ConCommandArgs)(ref args)).Count >= 1) ? ((ConCommandArgs)(ref args)).GetArgString(0).Trim().ToLowerInvariant() : string.Empty);
			int num;
			int num2;
			if (!(text == "done"))
			{
				num = ((text == "completed") ? 1 : 0);
				if (num == 0)
				{
					num2 = ChecklistStore.Clear();
					goto IL_004e;
				}
			}
			else
			{
				num = 1;
			}
			num2 = ChecklistStore.ClearCompleted();
			goto IL_004e;
			IL_004e:
			int num3 = num2;
			Print((num != 0) ? string.Format("Cleared {0} completed entr{1}.", num3, (num3 == 1) ? "y" : "ies") : $"Cleared the whole checklist ({num3}).");
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCFind(ConCommandArgs args)
		{
			if (((ConCommandArgs)(ref args)).Count < 1)
			{
				Print("Usage: uc_find <search>");
				return;
			}
			string argString = ((ConCommandArgs)(ref args)).GetArgString(0);
			List<string> list = UnlockIndex.Search(argString);
			if (list.Count == 0)
			{
				Print("No unlockable matches '" + argString + "'.");
			}
			else
			{
				PrintCandidates(argString, list);
			}
		}

		private static bool ResolveOne(string query, out string name)
		{
			name = null;
			List<string> list = UnlockIndex.Search(query);
			if (list.Count == 0)
			{
				Print("No unlockable matches '" + query + "'. Try uc_find.");
				return false;
			}
			if (list.Count > 1)
			{
				PrintCandidates(query, list);
				return false;
			}
			name = list[0];
			return true;
		}

		private static void PrintCandidates(string query, List<string> matches)
		{
			StringBuilder stringBuilder = new StringBuilder($"{matches.Count} match(es) for '{query}':\n");
			int num = 0;
			foreach (string match in matches)
			{
				if (num++ >= 30)
				{
					stringBuilder.AppendLine($"  ... and {matches.Count - 30} more. Narrow the search.");
					break;
				}
				UnlockEntry entry = UnlockIndex.GetEntry(match);
				stringBuilder.AppendLine(string.Format("  [{0}] {1,-48} {2}", entry.unlocked ? "x" : " ", match, entry.Title));
			}
			Print(stringBuilder.ToString());
		}

		private static bool Matches(string haystack, string needle)
		{
			if (!string.IsNullOrEmpty(haystack))
			{
				return haystack.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static string Strip(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text;
			}
			StringBuilder stringBuilder = new StringBuilder(text.Length);
			bool flag = false;
			foreach (char c in text)
			{
				switch (c)
				{
				case '<':
					flag = true;
					continue;
				case '>':
					flag = false;
					continue;
				}
				if (!flag)
				{
					stringBuilder.Append((c == '\n') ? ' ' : c);
				}
			}
			return stringBuilder.ToString().Trim();
		}

		private static void Print(string message)
		{
			Debug.Log((object)("[UnlockChecklist] " + message));
		}
	}
	internal static class LoadoutTagger
	{
		private static readonly FieldInfo RowsField = AccessTools.Field(typeof(LoadoutPanelController), "rows");

		private static readonly Type RowType = AccessTools.Inner(typeof(LoadoutPanelController), "Row");

		private static readonly Type RowDataType = AccessTools.Inner(typeof(LoadoutPanelController), "RowData");

		private static readonly FieldInfo RowDataField = ((RowType == null) ? null : AccessTools.Field(RowType, "rowData"));

		private static readonly FieldInfo ButtonField = ((RowDataType == null) ? null : AccessTools.Field(RowDataType, "button"));

		private static readonly FieldInfo DefIndexField = ((RowDataType == null) ? null : AccessTools.Field(RowDataType, "defIndex"));

		private static bool loadoutTaggingDisabled;

		private static bool survivorTaggingDisabled;

		private static readonly HashSet<string> warned = new HashSet<string>();

		[HarmonyPostfix]
		[HarmonyPatch(typeof(LoadoutPanelController), "Rebuild")]
		private static void DecorateLoadoutPanel(LoadoutPanelController __instance)
		{
			if (loadoutTaggingDisabled)
			{
				return;
			}
			try
			{
				if (RowsField == null || RowDataField == null || ButtonField == null || DefIndexField == null)
				{
					Disable(ref loadoutTaggingDisabled, "LoadoutPanelController no longer exposes the fields this reads; skills and skins cannot be tagged from the loadout panel. Survivor tagging and the uc_ commands still work.", null);
				}
				else
				{
					Decorate(__instance);
				}
			}
			catch (Exception exception)
			{
				Disable(ref loadoutTaggingDisabled, "Loadout panel tagging failed and has been switched off.", exception);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SurvivorIconController), "Rebuild")]
		private static void DecorateSurvivorIcon(SurvivorIconController __instance)
		{
			if (survivorTaggingDisabled)
			{
				return;
			}
			try
			{
				TagMarker.AttachToSurvivor(__instance);
				SurvivorDef survivorDef = __instance.survivorDef;
				if (Object.op_Implicit((Object)(object)survivorDef) && Object.op_Implicit((Object)(object)survivorDef.unlockableDef))
				{
					AppendHint(__instance.tooltipProvider);
				}
			}
			catch (Exception exception)
			{
				Disable(ref survivorTaggingDisabled, "Survivor tagging failed and has been switched off.", exception);
			}
		}

		private static void Decorate(LoadoutPanelController panel)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			MPEventSystemLocator component = ((Component)panel).GetComponent<MPEventSystemLocator>();
			MPEventSystem obj = (Object.op_Implicit((Object)(object)component) ? component.eventSystem : null);
			object obj2;
			if (obj == null)
			{
				obj2 = null;
			}
			else
			{
				LocalUser localUser = obj.localUser;
				obj2 = ((localUser != null) ? localUser.currentNetworkUser : null);
			}
			NetworkUser val = (NetworkUser)obj2;
			BodyIndex val2 = (BodyIndex)((!Object.op_Implicit((Object)(object)val)) ? (-1) : ((int)val.bodyIndexPreference));
			if ((int)val2 == -1)
			{
				return;
			}
			CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(val2);
			if (!Object.op_Implicit((Object)(object)bodyPrefabBodyComponent))
			{
				return;
			}
			GenericSkill[] components = ((Component)bodyPrefabBodyComponent).GetComponents<GenericSkill>();
			List<int> list = new List<int>();
			for (int i = 0; i < components.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)components[i]) && !components[i].hideInLoadoutSelect)
				{
					list.Add(i);
				}
			}
			SkinDef[] bodySkinDefs = SkinCatalog.GetBodySkinDefs(val2);
			if (!(RowsField.GetValue(panel) is IList list2))
			{
				return;
			}
			if (list2.Count != list.Count + 1)
			{
				WarnOnce($"Loadout panel has {list2.Count} row(s) where {list.Count + 1} were expected " + "for " + BodyCatalog.GetBodyName(val2) + "; skipping tag markers for it rather than risking a wrong mapping. Tag it with uc_tag instead.");
				return;
			}
			for (int j = 0; j < list2.Count; j++)
			{
				bool flag = j == list.Count;
				SkillFamily family = (flag ? null : components[list[j]].skillFamily);
				DecorateRow(list2[j], family, flag ? bodySkinDefs : null);
			}
		}

		private static void WarnOnce(string message)
		{
			if (warned.Add(message))
			{
				Plugin.Log.LogWarning((object)message);
			}
		}

		private static void DecorateRow(object row, SkillFamily family, SkinDef[] skins)
		{
			if (row == null || !(RowDataField.GetValue(row) is IList list))
			{
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				object obj = list[i];
				if (obj == null)
				{
					continue;
				}
				object? value = ButtonField.GetValue(obj);
				MPButton val = (MPButton)((value is MPButton) ? value : null);
				int num = (int)DefIndexField.GetValue(obj);
				if (Object.op_Implicit((Object)(object)val) && num >= 0)
				{
					UnlockableDef val2 = ((skins != null) ? GetSkinUnlockable(skins, num) : GetVariantUnlockable(family, num));
					if (Object.op_Implicit((Object)(object)val2))
					{
						TagMarker.Attach(((Component)val).gameObject, val2.cachedName);
						AppendHint(((Component)val).GetComponent<TooltipProvider>());
					}
				}
			}
		}

		private static UnlockableDef GetSkinUnlockable(SkinDef[] skins, int index)
		{
			if (index >= skins.Length || !Object.op_Implicit((Object)(object)skins[index]))
			{
				return null;
			}
			return skins[index].unlockableDef;
		}

		private static UnlockableDef GetVariantUnlockable(SkillFamily family, int index)
		{
			if (family?.variants == null || index >= family.variants.Length)
			{
				return null;
			}
			return family.variants[index].unlockableDef;
		}

		private static void AppendHint(TooltipProvider provider)
		{
			if (Plugin.AppendTooltipHint.Value && Object.op_Implicit((Object)(object)provider) && ((Behaviour)provider).enabled && !string.IsNullOrEmpty(provider.overrideBodyText))
			{
				string text = Hint();
				if (text != null)
				{
					provider.overrideBodyText = provider.overrideBodyText + "\n\n" + text;
				}
			}
		}

		private static string Hint()
		{
			bool value = Plugin.TagOnLeftClickWhenLocked.Value;
			bool value2 = Plugin.TagOnRightClick.Value;
			if (value && value2)
			{
				return "<style=cStack>Left or right click to add this to your unlock checklist.</style>";
			}
			if (value)
			{
				return "<style=cStack>Click to add this to your unlock checklist.</style>";
			}
			if (value2)
			{
				return "<style=cStack>Right click to add this to your unlock checklist.</style>";
			}
			return null;
		}

		private static void Disable(ref bool flag, string message, Exception exception)
		{
			flag = true;
			Plugin.Log.LogError((object)((exception == null) ? message : (message + " " + exception)));
		}
	}
	[BepInPlugin("com.bdub.UnlockChecklist", "UnlockChecklist", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.bdub.UnlockChecklist";

		public const string ModName = "UnlockChecklist";

		public const string ModVersion = "0.1.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static ConfigEntry<KeyboardShortcut> ToggleKey;

		internal static ConfigEntry<bool> TagOnLeftClickWhenLocked;

		internal static ConfigEntry<bool> TagOnRightClick;

		internal static ConfigEntry<bool> ShowCompleted;

		internal static ConfigEntry<bool> AppendTooltipHint;

		internal static ConfigEntry<bool> MarkTaggedInMenu;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			ChecklistStore.Load();
			harmony = new Harmony("com.bdub.UnlockChecklist");
			harmony.PatchAll(typeof(LoadoutTagger));
			Log.LogInfo((object)string.Format("{0} {1} loaded with {2} tag(s).", "UnlockChecklist", "0.1.0", ChecklistStore.Count));
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			ChecklistUI.Close();
		}

		private void BindConfig()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)107, Array.Empty<KeyCode>()), "Opens and closes the checklist. Works in a run and on the character select screen.");
			TagOnLeftClickWhenLocked = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "TagOnLeftClickWhenLocked", true, "Left-clicking a LOCKED entry in the character select tags it. Vanilla ignores that click entirely (locked buttons set disablePointerClick), so nothing is being overridden.");
			TagOnRightClick = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "TagOnRightClick", true, "Right-clicking any entry in the character select toggles its tag, locked or not. Vanilla binds nothing to right click here.");
			ShowCompleted = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowCompleted", true, "Keep tags you have since unlocked in the list, marked DONE. Off hides them, though they stay in the file until you clear them.");
			MarkTaggedInMenu = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "MarkTaggedInMenu", true, "Draw the orange corner pip and tint on tagged entries in the character select.");
			AppendTooltipHint = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "AppendTooltipHint", true, "Add a 'click to add to checklist' line to the tooltip of locked entries. Only touches tooltips the game has already filled in, and is rewritten from scratch on every rebuild.");
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = ToggleKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() && !IsTypingSomewhere())
			{
				ChecklistUI.Toggle();
			}
		}

		private static bool IsTypingSomewhere()
		{
			if (ConsoleWindow.IsShown())
			{
				return true;
			}
			GameObject val = (Object.op_Implicit((Object)(object)EventSystem.current) ? EventSystem.current.currentSelectedGameObject : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return false;
			}
			TMP_InputField component = val.GetComponent<TMP_InputField>();
			if (Object.op_Implicit((Object)(object)component) && component.isFocused)
			{
				return true;
			}
			InputField component2 = val.GetComponent<InputField>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				return component2.isFocused;
			}
			return false;
		}
	}
	internal class TagMarker : MonoBehaviour, IPointerClickHandler, IEventSystemHandler, IPointerDownHandler
	{
		private static readonly Color TaggedColor = new Color(0.95f, 0.62f, 0.18f, 1f);

		private static readonly Color DoneColor = new Color(0.38f, 0.8f, 0.42f, 1f);

		private string staticKey;

		private SurvivorIconController survivorSource;

		private Image tint;

		private Image pip;

		private string lastKey;

		private bool lastVisible;

		private bool lastDone;

		public string Key
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)survivorSource))
				{
					return staticKey;
				}
				SurvivorDef survivorDef = survivorSource.survivorDef;
				if (!Object.op_Implicit((Object)(object)survivorDef) || !Object.op_Implicit((Object)(object)survivorDef.unlockableDef))
				{
					return null;
				}
				return survivorDef.unlockableDef.cachedName;
			}
		}

		public static void Attach(GameObject target, string unlockableName)
		{
			if (Object.op_Implicit((Object)(object)target) && !string.IsNullOrEmpty(unlockableName))
			{
				TagMarker obj = target.GetComponent<TagMarker>() ?? target.AddComponent<TagMarker>();
				obj.staticKey = unlockableName;
				obj.survivorSource = null;
				obj.Refresh();
			}
		}

		public static void AttachToSurvivor(SurvivorIconController controller)
		{
			if (Object.op_Implicit((Object)(object)controller))
			{
				TagMarker obj = ((Component)controller).GetComponent<TagMarker>() ?? ((Component)controller).gameObject.AddComponent<TagMarker>();
				obj.staticKey = null;
				obj.survivorSource = controller;
				obj.Refresh();
			}
		}

		public void OnPointerDown(PointerEventData eventData)
		{
		}

		public void OnPointerClick(PointerEventData eventData)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			string key = Key;
			if (string.IsNullOrEmpty(key))
			{
				return;
			}
			if ((int)eventData.button == 1)
			{
				if (!Plugin.TagOnRightClick.Value)
				{
					return;
				}
			}
			else if ((int)eventData.button != 0 || !Plugin.TagOnLeftClickWhenLocked.Value || UnlockIndex.IsUnlocked(key))
			{
				return;
			}
			UnlockEntry entry = UnlockIndex.GetEntry(key);
			bool flag = ChecklistStore.Toggle(key);
			Plugin.Log.LogInfo((object)((flag ? "Tagged " : "Untagged ") + entry.Title + "  [" + key + "]"));
			Refresh();
		}

		private void LateUpdate()
		{
			Refresh();
		}

		private void Refresh()
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			string key = Key;
			bool flag = Plugin.MarkTaggedInMenu.Value && ChecklistStore.IsTagged(key);
			bool flag2 = flag && UnlockIndex.IsUnlocked(key);
			if (!(key == lastKey) || flag != lastVisible || flag2 != lastDone)
			{
				lastKey = key;
				lastVisible = flag;
				lastDone = flag2;
				if (flag && !Object.op_Implicit((Object)(object)pip))
				{
					Build();
				}
				if (Object.op_Implicit((Object)(object)pip))
				{
					Color val = (flag2 ? DoneColor : TaggedColor);
					((Graphic)pip).color = val;
					((Graphic)tint).color = new Color(val.r, val.g, val.b, 0.18f);
					((Component)pip).gameObject.SetActive(flag);
					((Component)tint).gameObject.SetActive(flag);
				}
			}
		}

		private void Build()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			tint = CreateOverlay("ChecklistTint", Vector2.zero, Vector2.one);
			pip = CreateOverlay("ChecklistPip", new Vector2(0.64f, 0.64f), new Vector2(0.96f, 0.96f));
		}

		private Image CreateOverlay(string name, Vector2 anchorMin, Vector2 anchorMax)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_003f: 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)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(((Component)this).transform, false);
			val2.anchorMin = anchorMin;
			val2.anchorMax = anchorMax;
			val2.offsetMin = Vector2.zero;
			val2.offsetMax = Vector2.zero;
			val.AddComponent<LayoutElement>().ignoreLayout = true;
			Image obj = val.AddComponent<Image>();
			((Graphic)obj).raycastTarget = false;
			return obj;
		}

		private void OnDestroy()
		{
			tint = null;
			pip = null;
		}
	}
	internal enum UnlockKind
	{
		Unresolved,
		Survivor,
		Skill,
		Skin
	}
	internal struct UnlockEntry
	{
		public string unlockableName;

		public UnlockKind kind;

		public string owner;

		public string label;

		public string slotLabel;

		public string requirement;

		public Sprite icon;

		public bool unlocked;

		public string Title
		{
			get
			{
				string text = (string.IsNullOrEmpty(owner) ? label : (owner + " - " + label));
				if (!string.IsNullOrEmpty(slotLabel))
				{
					return text + "  (" + slotLabel + ")";
				}
				return text;
			}
		}
	}
	internal static class UnlockIndex
	{
		private struct Descriptor
		{
			public UnlockKind kind;

			public string owner;

			public string label;

			public string slotLabel;

			public Sprite icon;
		}

		private static Dictionary<string, Descriptor> map;

		private static Dictionary<string, Descriptor> Map => map ?? (map = Build());

		public static void Invalidate()
		{
			map = null;
		}

		public static UnlockEntry GetEntry(string unlockableName)
		{
			UnlockEntry result = new UnlockEntry
			{
				unlockableName = unlockableName,
				kind = UnlockKind.Unresolved,
				label = unlockableName,
				unlocked = IsUnlocked(unlockableName)
			};
			if (Map.TryGetValue(unlockableName, out var value))
			{
				result.kind = value.kind;
				result.owner = value.owner;
				result.label = value.label;
				result.slotLabel = value.slotLabel;
				result.icon = value.icon;
			}
			AchievementDef achievement = GetAchievement(unlockableName);
			if (achievement != null)
			{
				result.requirement = Resolve(achievement.descriptionToken, null);
				if (result.kind == UnlockKind.Unresolved)
				{
					result.label = Resolve(achievement.nameToken, unlockableName);
				}
				if (!Object.op_Implicit((Object)(object)result.icon))
				{
					result.icon = achievement.GetAchievedIcon();
				}
			}
			if (string.IsNullOrEmpty(result.requirement))
			{
				UnlockableDef unlockableDef = GetUnlockableDef(unlockableName);
				result.requirement = (Object.op_Implicit((Object)(object)unlockableDef) ? unlockableDef.getHowToUnlockString() : null);
			}
			if (string.IsNullOrEmpty(result.requirement) || result.requirement == "???")
			{
				result.requirement = ((result.kind == UnlockKind.Unresolved) ? "Not installed in this modpack, or it has no unlock condition." : "No unlock condition is recorded for this.");
			}
			return result;
		}

		public static bool IsUnlocked(string unlockableName)
		{
			if (string.IsNullOrEmpty(unlockableName))
			{
				return true;
			}
			UnlockableDef unlockableDef = GetUnlockableDef(unlockableName);
			if (!Object.op_Implicit((Object)(object)unlockableDef))
			{
				return false;
			}
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				if (((readOnlyLocalUsers != null) ? readOnlyLocalUsers.userProfile : null) != null && readOnlyLocalUsers.userProfile.HasUnlockable(unlockableDef))
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsKnown(string unlockableName)
		{
			if (!string.IsNullOrEmpty(unlockableName))
			{
				return Map.ContainsKey(unlockableName);
			}
			return false;
		}

		public static List<string> Search(string query)
		{
			List<string> list = new List<string>();
			if (string.IsNullOrEmpty(query))
			{
				return list;
			}
			string text = query.Trim();
			if (Map.ContainsKey(text))
			{
				list.Add(text);
				return list;
			}
			foreach (KeyValuePair<string, Descriptor> item in Map)
			{
				Descriptor value = item.Value;
				if (Contains(item.Key, text) || Contains(value.label, text) || Contains(value.owner + " " + value.label, text))
				{
					list.Add(item.Key);
				}
			}
			return list;
		}

		private static bool Contains(string haystack, string needle)
		{
			if (!string.IsNullOrEmpty(haystack))
			{
				return haystack.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		public static UnlockableDef GetUnlockableDef(string unlockableName)
		{
			if (string.IsNullOrEmpty(unlockableName))
			{
				return null;
			}
			try
			{
				return UnlockableCatalog.GetUnlockableDef(unlockableName);
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static AchievementDef GetAchievement(string unlockableName)
		{
			try
			{
				return AchievementManager.GetAchievementDefFromUnlockable(unlockableName);
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static Dictionary<string, Descriptor> Build()
		{
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, Descriptor> dictionary = new Dictionary<string, Descriptor>(StringComparer.Ordinal);
			foreach (SurvivorDef orderedSurvivorDef in SurvivorCatalog.orderedSurvivorDefs)
			{
				if (!Object.op_Implicit((Object)(object)orderedSurvivorDef) || !Object.op_Implicit((Object)(object)orderedSurvivorDef.bodyPrefab))
				{
					continue;
				}
				CharacterBody component = orderedSurvivorDef.bodyPrefab.GetComponent<CharacterBody>();
				if (Object.op_Implicit((Object)(object)component))
				{
					string text = Resolve(orderedSurvivorDef.displayNameToken, orderedSurvivorDef.cachedName);
					if (Object.op_Implicit((Object)(object)orderedSurvivorDef.unlockableDef))
					{
						Add(dictionary, orderedSurvivorDef.unlockableDef.cachedName, new Descriptor
						{
							kind = UnlockKind.Survivor,
							owner = string.Empty,
							label = text,
							slotLabel = string.Empty,
							icon = null
						});
					}
					AddSkills(dictionary, component, text);
					AddSkins(dictionary, component.bodyIndex, text);
				}
			}
			Plugin.Log.LogInfo((object)("Indexed " + dictionary.Count + " unlockable(s) across " + SurvivorCatalog.survivorCount + " survivor(s)."));
			return dictionary;
		}

		private static void AddSkills(Dictionary<string, Descriptor> result, CharacterBody prefabBody, string survivorName)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			SkillLocator component = ((Component)prefabBody).GetComponent<SkillLocator>();
			GenericSkill[] components = ((Component)prefabBody).GetComponents<GenericSkill>();
			foreach (GenericSkill val in components)
			{
				SkillFamily val2 = (Object.op_Implicit((Object)(object)val) ? val.skillFamily : null);
				if ((Object)(object)val2 == (Object)null || val2.variants == null)
				{
					continue;
				}
				string slotLabel = GetSlotLabel(component, val);
				Variant[] variants = val2.variants;
				foreach (Variant val3 in variants)
				{
					if (Object.op_Implicit((Object)(object)val3.unlockableDef) && Object.op_Implicit((Object)(object)val3.skillDef))
					{
						Add(result, val3.unlockableDef.cachedName, new Descriptor
						{
							kind = UnlockKind.Skill,
							owner = survivorName,
							label = Resolve(val3.skillDef.skillNameToken, val3.skillDef.skillName),
							slotLabel = slotLabel,
							icon = val3.skillDef.icon
						});
					}
				}
			}
		}

		private static void AddSkins(Dictionary<string, Descriptor> result, BodyIndex bodyIndex, string survivorName)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if ((int)bodyIndex == -1)
			{
				return;
			}
			SkinDef[] bodySkinDefs = SkinCatalog.GetBodySkinDefs(bodyIndex);
			if (bodySkinDefs == null)
			{
				return;
			}
			SkinDef[] array = bodySkinDefs;
			foreach (SkinDef val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.unlockableDef))
				{
					Add(result, val.unlockableDef.cachedName, new Descriptor
					{
						kind = UnlockKind.Skin,
						owner = survivorName,
						label = Resolve(val.nameToken, ((Object)val).name),
						slotLabel = "Skin",
						icon = val.icon
					});
				}
			}
		}

		private static string GetSlotLabel(SkillLocator locator, GenericSkill slot)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected I4, but got Unknown
			if (!string.IsNullOrWhiteSpace(slot.loadoutTitleToken))
			{
				return Resolve(slot.loadoutTitleToken, slot.loadoutTitleToken);
			}
			SkillSlot val = (SkillSlot)((!Object.op_Implicit((Object)(object)locator)) ? (-1) : ((int)locator.FindSkillSlot(slot)));
			return Resolve((int)val switch
			{
				0 => "LOADOUT_SKILL_PRIMARY", 
				1 => "LOADOUT_SKILL_SECONDARY", 
				2 => "LOADOUT_SKILL_UTILITY", 
				3 => "LOADOUT_SKILL_SPECIAL", 
				_ => "LOADOUT_SKILL_MISC", 
			}, string.Empty);
		}

		private static void Add(Dictionary<string, Descriptor> result, string name, Descriptor descriptor)
		{
			if (!string.IsNullOrEmpty(name) && !result.ContainsKey(name))
			{
				result[name] = descriptor;
			}
		}

		private static string Resolve(string token, string fallback)
		{
			if (string.IsNullOrEmpty(token))
			{
				return fallback;
			}
			string text = Language.GetString(token);
			if (!string.IsNullOrEmpty(text) && !(text == token))
			{
				return text;
			}
			return fallback;
		}
	}
}