Decompiled source of Gentlemens Mod Manager v2.1.0

ModManager/ModManager.dll

Decompiled 8 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using AGD.ModAPI;
using AGD.Modding;
using AGDKit;
using Character;
using Core;
using DisputeLib;
using FMOD;
using FMOD.Studio;
using FMODUnity;
using FishNet;
using FishNet.Broadcast;
using FishNet.Managing;
using FishNet.Object;
using FishNet.Serializing;
using FishNet.Transporting;
using Game;
using HeldItems;
using Items;
using Menus;
using Menus.Utility;
using Newtonsoft.Json.Linq;
using Player;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Playables;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Util;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ModManager
{
	internal static class FriendPicker
	{
		private class Friend
		{
			public string Name;

			public ulong Id;

			public Image Face;

			public TextMeshProUGUI Label;
		}

		private static List<Friend> _friends;

		private static TextMeshProUGUI _current;

		private static GameObject _clear;

		private static RectTransform _list;

		public static bool Wanted(string rootPath)
		{
			try
			{
				return File.Exists(Path.Combine(Path.Combine(rootPath, "assets"), "friend-picker.txt"));
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static string FileOf(string modId)
		{
			return Path.Combine(Path.Combine(Path.Combine(Application.persistentDataPath, "ModData"), modId), "target.json");
		}

		private static string Current(string modId, out ulong id)
		{
			id = 0uL;
			try
			{
				string path = FileOf(modId);
				if (!File.Exists(path))
				{
					return "";
				}
				string json = File.ReadAllText(path);
				ulong.TryParse(Field(json, "steamId"), out id);
				return Field(json, "name");
			}
			catch (Exception)
			{
				return "";
			}
		}

		private static string Field(string json, string key)
		{
			int num = json.IndexOf("\"" + key + "\"", StringComparison.Ordinal);
			if (num < 0)
			{
				return "";
			}
			num = json.IndexOf(':', num);
			if (num < 0)
			{
				return "";
			}
			int num2 = json.IndexOf('"', num);
			if (num2 < 0)
			{
				return "";
			}
			int num3 = json.IndexOf('"', num2 + 1);
			if (num3 < 0)
			{
				return "";
			}
			return json.Substring(num2 + 1, num3 - num2 - 1);
		}

		private static void Save(string modId, Friend f)
		{
			try
			{
				string path = FileOf(modId);
				Directory.CreateDirectory(Path.GetDirectoryName(path));
				if (f == null)
				{
					if (File.Exists(path))
					{
						File.Delete(path);
					}
					return;
				}
				string text = f.Name.Replace("\\", "").Replace("\"", "");
				File.WriteAllText(path, "{\"steamId\":\"" + f.Id + "\",\"name\":\"" + text + "\"}");
			}
			catch (Exception ex)
			{
				Kit.Warn("friend picker: " + ex.Message);
			}
		}

		private static void Load()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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)
			_friends = new List<Friend>();
			try
			{
				int friendCount = SteamFriends.GetFriendCount((EFriendFlags)4);
				for (int i = 0; i < friendCount; i++)
				{
					CSteamID friendByIndex = SteamFriends.GetFriendByIndex(i, (EFriendFlags)4);
					_friends.Add(new Friend
					{
						Id = friendByIndex.m_SteamID,
						Name = SteamFriends.GetFriendPersonaName(friendByIndex)
					});
				}
				_friends.Sort((Friend a, Friend b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
			}
			catch (Exception ex)
			{
				Kit.Warn("friend picker: steam friends unavailable: " + ex.Message);
			}
		}

		public static void Build(RectTransform parent, string modId)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Expected O, but got Unknown
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Expected O, but got Unknown
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Expected O, but got Unknown
			Ui.Size(((Component)Ui.Text((Transform)(object)parent, "TARGET", 28f, Ui.Gold, (TextAlignmentOptions)513)).gameObject, -1f, 44f);
			string selfFlag = Path.Combine(Path.GetDirectoryName(FileOf(modId)), "self.flag");
			RectTransform obj = Ui.Node("Self", (Transform)(object)parent);
			((HorizontalOrVerticalLayoutGroup)Ui.HGroup(((Component)obj).gameObject, 16f, null, (TextAnchor)3)).childForceExpandHeight = false;
			Ui.Size(((Component)obj).gameObject, -1f, 56f);
			Ui.Checkbox((Transform)(object)obj, File.Exists(selfFlag), delegate(bool want)
			{
				try
				{
					Directory.CreateDirectory(Path.GetDirectoryName(selfFlag));
					if (want)
					{
						File.WriteAllText(selfFlag, "1");
					}
					else
					{
						File.Delete(selfFlag);
					}
				}
				catch (Exception ex)
				{
					Kit.Warn("friend picker: " + ex.Message);
				}
			}, out var _, 48f);
			Ui.Text((Transform)(object)obj, "Target myself (solo testing)", 27f, Ui.Dark, (TextAlignmentOptions)513);
			_current = Ui.Text((Transform)(object)parent, "", 27f, Ui.Dark, (TextAlignmentOptions)513);
			Ui.Size(((Component)_current).gameObject, -1f, 38f);
			RectTransform obj2 = Ui.Node("Buttons", (Transform)(object)parent);
			((HorizontalOrVerticalLayoutGroup)Ui.HGroup(((Component)obj2).gameObject, 12f, null, (TextAnchor)3)).childForceExpandHeight = false;
			Ui.Size(((Component)obj2).gameObject, -1f, 66f);
			Color bg = default(Color);
			((Color)(ref bg))..ctor(0.965f, 0.961f, 0.973f);
			Ui.Pill((Transform)(object)obj2, "REFRESH", bg, Ui.Dark, 220f, 60f, (UnityAction)delegate
			{
				Load();
				Fill(parent, modId, null);
			}, 27f);
			_clear = ((Component)((Component)Ui.Pill((Transform)(object)obj2, "CLEAR", bg, Ui.Dark, 190f, 60f, (UnityAction)delegate
			{
				Save(modId, null);
				Recolor(modId);
			}, 27f)).transform.parent).gameObject;
			ScrollRect sr;
			RectTransform list = Ui.Scroll((Transform)(object)parent, "Friends", out sr, 8f, new RectOffset(6, 6, 6, 10));
			Ui.Size(((Component)sr).gameObject, -1f, 330f);
			if (_friends == null)
			{
				Load();
			}
			Fill(parent, modId, list);
		}

		private static void Fill(RectTransform parent, string modId, RectTransform list)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)list != (Object)null)
			{
				_list = list;
			}
			if ((Object)(object)_list == (Object)null)
			{
				return;
			}
			Ui.Clear((Transform)(object)_list);
			foreach (Friend friend in _friends)
			{
				Friend fr = friend;
				Image val = Ui.Card((Transform)(object)_list, "Friend", Ui.RowBg);
				Ui.Size(((Component)((Transform)((Graphic)val).rectTransform).parent).gameObject, -1f, 58f);
				Button obj = ((Component)val).gameObject.AddComponent<Button>();
				((Selectable)obj).targetGraphic = (Graphic)(object)val;
				((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
				{
					Save(modId, fr);
					Recolor(modId);
				});
				TextMeshProUGUI val2 = Ui.Text((Transform)(object)((Graphic)val).rectTransform, friend.Name, 27f, Ui.Dark, (TextAlignmentOptions)513);
				Ui.Stretch(((TMP_Text)val2).rectTransform, 18f, 0f, 18f);
				friend.Face = val;
				friend.Label = val2;
			}
			Recolor(modId);
		}

		private static void Recolor(string modId)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			ulong id;
			string text = Current(modId, out id);
			if ((Object)(object)_current != (Object)null)
			{
				((TMP_Text)_current).text = ((id == 0L) ? "Nobody picked." : ("Target: " + text));
			}
			if ((Object)(object)_clear != (Object)null)
			{
				_clear.SetActive(id != 0);
			}
			if (_friends == null)
			{
				return;
			}
			foreach (Friend friend in _friends)
			{
				if (!((Object)(object)friend.Face == (Object)null))
				{
					bool flag = friend.Id == id && id != 0;
					((Graphic)friend.Face).color = (flag ? Ui.Red : Ui.RowBg);
					((Graphic)friend.Label).color = (flag ? Ui.RedText : Ui.Dark);
				}
			}
		}
	}
	internal static class MenuHook
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Func<Component, bool> <>9__7_1;

			public static UnityAction <>9__7_0;

			internal bool <Install>b__7_1(Component c)
			{
				if ((Object)(object)c != (Object)null)
				{
					if (!(((object)c).GetType().Name == "GameObjectLocalizer"))
					{
						return ((object)c).GetType().Name == "LocalizeStringEvent";
					}
					return true;
				}
				return false;
			}

			internal void <Install>b__7_0()
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				MenuManager.Instance.SetPage(Page);
			}
		}

		public const int PageKey = 100;

		public static MenuPage Page => (MenuPage)100;

		public static bool Ready(out string why)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_0084: Invalid comparison between Unknown and I4
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			why = null;
			if ((Object)(object)MenuManager.Instance == (Object)null)
			{
				why = "no MenuManager";
				return false;
			}
			Transform val = LayoutOf();
			if ((Object)(object)val == (Object)null)
			{
				why = "no main menu layout";
				return false;
			}
			Transform val2 = val.Find("Quit Main Menu Button");
			Transform val3 = val.Find("Credits Main Menu Button");
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
			{
				why = "main menu buttons not built yet";
				return false;
			}
			Selectable component = ((Component)val2).GetComponent<Selectable>();
			if (!((Object)(object)component == (Object)null))
			{
				Navigation navigation = component.navigation;
				if ((int)((Navigation)(ref navigation)).mode == 4)
				{
					navigation = component.navigation;
					if (!((Object)(object)((Navigation)(ref navigation)).selectOnUp == (Object)null))
					{
						return true;
					}
				}
			}
			why = "main menu navigation not wired yet";
			return false;
		}

		public static bool Installed()
		{
			Transform val = LayoutOf();
			if ((Object)(object)val != (Object)null)
			{
				return (Object)(object)val.Find("Mods Main Menu Button") != (Object)null;
			}
			return false;
		}

		private static Transform LayoutOf()
		{
			Canvas[] array = Object.FindObjectsOfType<Canvas>(true);
			foreach (Canvas val in array)
			{
				if (!(((Object)val).name != "Main") && !((Object)(object)((Component)val).transform.parent == (Object)null) && !(((Object)((Component)val).transform.parent).name != "Canvases"))
				{
					return ((Component)val).transform.Find("VerticalLayoutGroup");
				}
			}
			return null;
		}

		public static void Uninstall()
		{
			//IL_0027: 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_00d7: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			MenuManager instance = MenuManager.Instance;
			IDictionary dictionary = (((Object)(object)instance != (Object)null) ? (Reflect.Get<object>(instance, "menuPages") as IDictionary) : null);
			if (dictionary != null && dictionary.Contains(Page))
			{
				dictionary.Remove(Page);
			}
			Transform val = LayoutOf();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform val2 = val.Find("Mods Main Menu Button");
			if ((Object)(object)val2 != (Object)null)
			{
				Transform val3 = val.Find("Credits Main Menu Button");
				Transform val4 = val.Find("Quit Main Menu Button");
				Object.Destroy((Object)(object)((Component)val2).gameObject);
				Selectable val5 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<Selectable>() : null);
				Selectable val6 = (((Object)(object)val4 != (Object)null) ? ((Component)val4).GetComponent<Selectable>() : null);
				if ((Object)(object)val5 != (Object)null && (Object)(object)val6 != (Object)null)
				{
					Navigation navigation = val5.navigation;
					((Navigation)(ref navigation)).selectOnDown = val6;
					val5.navigation = navigation;
					Navigation navigation2 = val6.navigation;
					((Navigation)(ref navigation2)).selectOnUp = val5;
					val6.navigation = navigation2;
				}
			}
			Transform val7 = val.parent.parent.Find("Mods");
			if ((Object)(object)val7 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val7).gameObject);
			}
		}

		public static ModsPage Install()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Expected O, but got Unknown
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Expected O, but got Unknown
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Expected O, but got Unknown
			MenuManager instance = MenuManager.Instance;
			Transform val = LayoutOf();
			Transform parent = val.parent.parent;
			Transform val2 = val.Find("Credits Main Menu Button");
			Transform val3 = val.Find("Quit Main Menu Button");
			Canvas componentInParent = ((Component)val).GetComponentInParent<Canvas>();
			GameObject val4 = new GameObject("Mods", new Type[1] { typeof(RectTransform) });
			val4.layer = 5;
			val4.SetActive(false);
			val4.transform.SetParent(parent, false);
			Canvas obj = val4.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = ((!((Object)(object)componentInParent != (Object)null)) ? 1 : (componentInParent.sortingOrder + 1));
			CanvasScaler obj2 = val4.AddComponent<CanvasScaler>();
			CanvasScaler val5 = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).GetComponent<CanvasScaler>() : null);
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = (Vector2)(((Object)(object)val5 != (Object)null) ? val5.referenceResolution : new Vector2(1920f, 1080f));
			obj2.screenMatchMode = (ScreenMatchMode)(((Object)(object)val5 != (Object)null) ? ((int)val5.screenMatchMode) : 0);
			obj2.matchWidthOrHeight = (((Object)(object)val5 != (Object)null) ? val5.matchWidthOrHeight : 0.5f);
			val4.AddComponent<GraphicRaycaster>();
			val4.AddComponent<CanvasGroup>();
			ModsPage modsPage = val4.AddComponent<ModsPage>();
			modsPage.Build();
			((Reflect.Get<object>(instance, "menuPages") as IDictionary) ?? throw new InvalidOperationException("MenuManager.menuPages not found"))[Page] = new Transform[1] { val4.transform };
			GameObject val6 = Object.Instantiate<GameObject>(((Component)val2).gameObject, val);
			((Object)val6).name = "Mods Main Menu Button";
			val6.transform.SetSiblingIndex(val3.GetSiblingIndex());
			TextButton component = val6.GetComponent<TextButton>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
			TMP_Text[] componentsInChildren = val6.GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].text = "MODS";
			}
			Component[] array = (from c in val6.GetComponentsInChildren<Component>(true)
				where (Object)(object)c != (Object)null && (((object)c).GetType().Name == "GameObjectLocalizer" || ((object)c).GetType().Name == "LocalizeStringEvent")
				select c).ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				Object.Destroy((Object)(object)array[i]);
			}
			Button component2 = val6.GetComponent<Button>();
			Reflect.Set(component2, "m_OnClick", (object)new ButtonClickedEvent());
			ButtonClickedEvent onClick = component2.onClick;
			object obj3 = <>c.<>9__7_0;
			if (obj3 == null)
			{
				UnityAction val7 = delegate
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					MenuManager.Instance.SetPage(Page);
				};
				<>c.<>9__7_0 = val7;
				obj3 = (object)val7;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj3);
			AutoSizeTextContainer component3 = val6.GetComponent<AutoSizeTextContainer>();
			if ((Object)(object)component3 != (Object)null)
			{
				try
				{
					component3.Refresh();
				}
				catch (Exception)
				{
				}
			}
			Selectable component4 = ((Component)val2).GetComponent<Selectable>();
			Selectable component5 = ((Component)val3).GetComponent<Selectable>();
			Selectable component6 = val6.GetComponent<Selectable>();
			Navigation navigation = component6.navigation;
			((Navigation)(ref navigation)).mode = (Mode)4;
			((Navigation)(ref navigation)).selectOnUp = component4;
			((Navigation)(ref navigation)).selectOnDown = component5;
			component6.navigation = navigation;
			Navigation navigation2 = component4.navigation;
			((Navigation)(ref navigation2)).selectOnDown = component6;
			component4.navigation = navigation2;
			Navigation navigation3 = component5.navigation;
			((Navigation)(ref navigation3)).selectOnUp = component6;
			component5.navigation = navigation3;
			LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)val);
			try
			{
				instance.RegisterPage(Page, modsPage.DefaultSelectable);
			}
			catch (Exception ex2)
			{
				Kit.Warn("RegisterPage: " + ex2.Message);
			}
			Kit.Log("Mods page registered (page key " + 100 + "), MODS button added");
			return modsPage;
		}
	}
	internal class ModsPage : MonoBehaviour
	{
		private class ListRow
		{
			public DiscoveredMod Mod;

			public Image Edge;

			public Image Face;

			public TextMeshProUGUI Name;

			public TextMeshProUGUI Sub;

			public Action<bool> RefreshCheck;

			public Button Check;
		}

		private class Content
		{
			public List<KeyValuePair<string, Sprite>> Perks = new List<KeyValuePair<string, Sprite>>();

			public List<KeyValuePair<string, Sprite>> Items = new List<KeyValuePair<string, Sprite>>();

			public List<TierEditor.Entry> Cards = new List<TierEditor.Entry>();
		}

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

			public static Func<DiscoveredMod, bool> <>9__45_1;

			public static UnityAction <>9__48_0;

			public static Func<DiscoveredMod, bool> <>9__50_0;

			public static Func<DiscoveredMod, string> <>9__50_1;

			public static Func<LoadedModPlugin, bool> <>9__52_0;

			public static Func<LoadedModPlugin, DiscoveredMod> <>9__52_1;

			public static Func<DiscoveredMod, string> <>9__52_2;

			internal bool <Open>b__45_1(DiscoveredMod m)
			{
				return m.ModId != Kit.ModId;
			}

			internal void <BuildFooter>b__48_0()
			{
				OpenFolder(ModPaths.InstallModsPath);
			}

			internal bool <Mods>b__50_0(DiscoveredMod m)
			{
				if (m != null)
				{
					return !string.IsNullOrEmpty(m.ModId);
				}
				return false;
			}

			internal string <Mods>b__50_1(DiscoveredMod m)
			{
				return m.Name ?? m.ModId;
			}

			internal bool <PartyCode>b__52_0(LoadedModPlugin p)
			{
				if (p != null)
				{
					return p.Mod != null;
				}
				return false;
			}

			internal DiscoveredMod <PartyCode>b__52_1(LoadedModPlugin p)
			{
				return p.Mod;
			}

			internal string <PartyCode>b__52_2(DiscoveredMod m)
			{
				return m.ModId;
			}
		}

		private const float WinW = 1560f;

		private const float WinH = 900f;

		private const float HeaderH = 104f;

		private const float FooterH = 124f;

		private static readonly Color GoodTxt = new Color(0.17f, 0.58f, 0.28f);

		private static readonly Color WarnTxt = new Color(0.78f, 0.52f, 0.1f);

		private static readonly Color PillBg = new Color(0.965f, 0.961f, 0.973f);

		private static readonly Color ErrTxt = new Color(1f, 0.64f, 0.6f);

		private static readonly Color OnDark = new Color(0.8f, 0.79f, 0.8f);

		private bool _built;

		private bool _lockSeen;

		private bool _tierLockSeen;

		private string _selected;

		private int _tab;

		private string _partyCode = "";

		private string _message;

		private List<DiscoveredMod> _mods = new List<DiscoveredMod>();

		private readonly Dictionary<string, ListRow> _rows = new Dictionary<string, ListRow>();

		private readonly Dictionary<string, Content> _content = new Dictionary<string, Content>();

		private RectTransform _listContent;

		private RectTransform _detailContent;

		private RectTransform _dragLayer;

		private Image _baseEdge;

		private TierEditor _editor;

		private ScrollRect _listScroll;

		private ScrollRect _detailScroll;

		private TextMeshProUGUI _count;

		private TextMeshProUGUI _code;

		private TextMeshProUGUI _title;

		private TextMeshProUGUI _subtitle;

		private TextMeshProUGUI _footMsg;

		private Button _tabAbout;

		private Button _tabOptions;

		private Button _tabRarity;

		private Button _undo;

		private Button _apply;

		private Button _back;

		private GameObject _tabsRow;

		public Selectable DefaultSelectable => (Selectable)(object)_back;

		private void OnEnable()
		{
			if (!_built)
			{
				Build();
			}
			Open();
		}

		private void Update()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			MenuManager instance = MenuManager.Instance;
			if ((Object)(object)instance == (Object)null || instance.Page.Value != MenuHook.Page)
			{
				return;
			}
			if (_lockSeen != Options.FromHost)
			{
				_lockSeen = Options.FromHost;
				if (_tab == 1)
				{
					RebuildDetails();
				}
			}
			bool flag = PerkTiers.Available && PerkTiers.Locked;
			if (_tierLockSeen != flag)
			{
				_tierLockSeen = flag;
				if (_tab == 2)
				{
					RebuildDetails();
				}
			}
			Keyboard current = Keyboard.current;
			Gamepad current2 = Gamepad.current;
			if ((current != null && ((ButtonControl)current.escapeKey).wasPressedThisFrame) || (current2 != null && current2.buttonEast.wasPressedThisFrame))
			{
				Back();
			}
		}

		private static void Back()
		{
			MenuManager instance = MenuManager.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.SetPageToStart();
			}
		}

		private void Open()
		{
			_mods = Mods();
			_partyCode = PartyCode();
			_message = null;
			if (_selected == null || (_selected != "base-game" && !_mods.Any((DiscoveredMod m) => m.ModId == _selected)))
			{
				_selected = (((IEnumerable<DiscoveredMod>)_mods).FirstOrDefault((Func<DiscoveredMod, bool>)((DiscoveredMod m) => m.ModId != Kit.ModId)) ?? _mods.FirstOrDefault())?.ModId;
			}
			((TMP_Text)_code).text = _partyCode;
			BuildList();
			RebuildDetails();
			RefreshFooter();
		}

		public void Build()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Expected O, but got Unknown
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03be: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Expected O, but got Unknown
			//IL_03da: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Expected O, but got Unknown
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_042c: Unknown result type (might be due to invalid IL or missing references)
			//IL_043b: Expected O, but got Unknown
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			if (!_built)
			{
				_built = true;
				Ui.Init();
				RectTransform parent = (RectTransform)((Component)this).transform;
				Ui.Stretch(((Graphic)Ui.Img((Transform)(object)parent, "Dim", new Color(0f, 0f, 0f, 0.28f), null, raycast: true)).rectTransform);
				RectTransform val = Ui.Node("Window", (Transform)(object)parent);
				Ui.Anchor(val, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(1560f, 900f));
				if ((Object)(object)Ui.Shadow != (Object)null)
				{
					Ui.Stretch(((Graphic)Ui.Img((Transform)(object)val, "Shadow", Color.white, Ui.Shadow)).rectTransform, -40f, -70f, -40f, -10f);
				}
				Image obj = Ui.Img((Transform)(object)val, "Mask", Ui.Body, Ui.Round, raycast: true);
				Ui.Stretch(((Graphic)obj).rectTransform);
				((Component)obj).gameObject.AddComponent<Mask>();
				RectTransform parent2 = (_dragLayer = ((Graphic)obj).rectTransform);
				BuildHeader(parent2);
				BuildFooter(parent2);
				RectTransform val2 = Ui.Node("Body", (Transform)(object)parent2);
				Ui.Stretch(val2, 0f, 124f, 0f, 104f);
				Ui.HGroup(((Component)val2).gameObject, 30f, new RectOffset(34, 34, 28, 28), (TextAnchor)0);
				RectTransform val3 = Ui.Node("Left", (Transform)(object)val2);
				Ui.Size(((Component)val3).gameObject, 560f, -1f, 0f, 1f);
				Ui.VGroup(((Component)val3).gameObject, 12f, null, (TextAnchor)0);
				_count = Ui.Text((Transform)(object)val3, "", 26f, Ui.Muted, (TextAlignmentOptions)513);
				Ui.Size(((Component)_count).gameObject, -1f, 34f);
				_listContent = Ui.Scroll((Transform)(object)val3, "List", out _listScroll, 12f, new RectOffset(8, 8, 8, 12));
				Ui.Size(((Component)_listScroll).gameObject, -1f, -1f, 1f, 1f);
				Ui.Size(((Component)Ui.Text((Transform)(object)val3, "Everyone in a party needs the same mods. Friends whose party codes match can play together.", 21f, Ui.Muted, (TextAlignmentOptions)513, wrap: true)).gameObject, -1f, 64f);
				RectTransform val4 = Ui.Node("Right", (Transform)(object)val2);
				Ui.Size(((Component)val4).gameObject, -1f, -1f, 1f, 1f);
				Ui.VGroup(((Component)val4).gameObject, 12f, null, (TextAnchor)0);
				_title = Ui.Text((Transform)(object)val4, "", 46f, Ui.Dark, (TextAlignmentOptions)513);
				Ui.Size(((Component)_title).gameObject, -1f, 56f);
				_subtitle = Ui.Text((Transform)(object)val4, "", 24f, Ui.Muted, (TextAlignmentOptions)513);
				Ui.Size(((Component)_subtitle).gameObject, -1f, 32f);
				RectTransform val5 = Row((Transform)(object)val4, 14f, 66f);
				_tabsRow = ((Component)val5).gameObject;
				_tabAbout = Ui.Pill((Transform)(object)val5, "ABOUT", PillBg, Ui.Dark, 220f, 62f, (UnityAction)delegate
				{
					_tab = 0;
					RebuildDetails();
				}, 28f);
				_tabOptions = Ui.Pill((Transform)(object)val5, "OPTIONS", PillBg, Ui.Dark, 280f, 62f, (UnityAction)delegate
				{
					_tab = 1;
					RebuildDetails();
				}, 28f);
				_tabRarity = Ui.Pill((Transform)(object)val5, "PERK RARITY", PillBg, Ui.Dark, 300f, 62f, (UnityAction)delegate
				{
					_tab = 2;
					RebuildDetails();
				}, 28f);
				_detailContent = Ui.Scroll((Transform)(object)val4, "Details", out _detailScroll, 12f, new RectOffset(6, 6, 8, 28));
				Ui.Size(((Component)_detailScroll).gameObject, -1f, -1f, 1f, 1f);
			}
		}

		private void BuildHeader(RectTransform parent)
		{
			//IL_0006: 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_0032: 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_0046: 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_006f: 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_00ad: 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_00cb: 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)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			Image val = Ui.Img((Transform)(object)parent, "Header", Ui.Dark, null, raycast: true);
			Ui.Anchor(((Graphic)val).rectTransform, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0.5f, 1f), Vector2.zero, new Vector2(0f, 104f));
			TextMeshProUGUI obj = Ui.Text((Transform)(object)((Graphic)val).rectTransform, "MODS", 68f, Ui.HeaderText, (TextAlignmentOptions)513);
			Ui.Anchor(((TMP_Text)obj).rectTransform, new Vector2(0f, 0f), new Vector2(0.5f, 1f), new Vector2(0f, 0.5f), new Vector2(40f, 0f), new Vector2(0f, 0f));
			((TMP_Text)obj).alignment = (TextAlignmentOptions)513;
			Ui.Anchor(((TMP_Text)Ui.Text((Transform)(object)((Graphic)val).rectTransform, "PARTY CODE", 21f, OnDark, (TextAlignmentOptions)516)).rectTransform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-40f, -14f), new Vector2(400f, 28f));
			_code = Ui.Text((Transform)(object)((Graphic)val).rectTransform, "", 42f, Ui.Gold, (TextAlignmentOptions)516);
			Ui.Anchor(((TMP_Text)_code).rectTransform, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-40f, 12f), new Vector2(400f, 56f));
		}

		private void BuildFooter(RectTransform parent)
		{
			//IL_0006: 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_0032: 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_0046: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Expected O, but got Unknown
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Expected O, but got Unknown
			//IL_013a: 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_0145: Expected O, but got Unknown
			Image val = Ui.Img((Transform)(object)parent, "Footer", Ui.Dark, null, raycast: true);
			Ui.Anchor(((Graphic)val).rectTransform, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(0.5f, 0f), Vector2.zero, new Vector2(0f, 124f));
			((HorizontalOrVerticalLayoutGroup)Ui.HGroup(((Component)val).gameObject, 18f, new RectOffset(34, 34, 0, 0), (TextAnchor)3)).childForceExpandHeight = false;
			_back = Ui.Pill((Transform)(object)((Graphic)val).rectTransform, "BACK", PillBg, Ui.Dark, 220f, 78f, new UnityAction(Back), 34f);
			_footMsg = Ui.Text((Transform)(object)((Graphic)val).rectTransform, "", 25f, Ui.Gold, (TextAlignmentOptions)513, wrap: true);
			Ui.Size(((Component)_footMsg).gameObject, -1f, -1f, 1f, 0f);
			RectTransform rectTransform = ((Graphic)val).rectTransform;
			Color pillBg = PillBg;
			Color dark = Ui.Dark;
			object obj = <>c.<>9__48_0;
			if (obj == null)
			{
				UnityAction val2 = delegate
				{
					OpenFolder(ModPaths.InstallModsPath);
				};
				<>c.<>9__48_0 = val2;
				obj = (object)val2;
			}
			Ui.Pill((Transform)(object)rectTransform, "FOLDER", pillBg, dark, 210f, 78f, (UnityAction)obj, 30f);
			_undo = Ui.Pill((Transform)(object)((Graphic)val).rectTransform, "UNDO", PillBg, Ui.Dark, 190f, 78f, (UnityAction)delegate
			{
				Pending.Clear();
				_message = null;
				RefreshAll();
			}, 30f);
			_apply = Ui.Pill((Transform)(object)((Graphic)val).rectTransform, "APPLY & QUIT", Ui.Red, Ui.RedText, 360f, 78f, new UnityAction(ApplyAndQuit), 32f);
		}

		private static RectTransform Row(Transform parent, float spacing, float h)
		{
			RectTransform val = Ui.Node("Row", parent);
			((HorizontalOrVerticalLayoutGroup)Ui.HGroup(((Component)val).gameObject, spacing, null, (TextAnchor)3)).childForceExpandHeight = false;
			if (h > 0f)
			{
				Ui.Size(((Component)val).gameObject, -1f, h);
			}
			return val;
		}

		private static List<DiscoveredMod> Mods()
		{
			IReadOnlyList<DiscoveredMod> mods = LocalModProvider.Mods;
			if (mods == null)
			{
				return new List<DiscoveredMod>();
			}
			return mods.Where((DiscoveredMod m) => m != null && !string.IsNullOrEmpty(m.ModId)).OrderBy<DiscoveredMod, string>((DiscoveredMod m) => m.Name ?? m.ModId, StringComparer.OrdinalIgnoreCase).ToList();
		}

		private static bool IsLoaded(DiscoveredMod m)
		{
			return ModAssemblyLoader.LoadedPlugins?.Any((LoadedModPlugin p) => p != null && p.Mod != null && p.Mod.ModId == m.ModId) ?? false;
		}

		private static string PartyCode()
		{
			IReadOnlyList<LoadedModPlugin> loadedPlugins = ModAssemblyLoader.LoadedPlugins;
			if (loadedPlugins == null || loadedPlugins.Count == 0)
			{
				return "no mods";
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (DiscoveredMod item in (from p in loadedPlugins
				where p != null && p.Mod != null
				select p.Mod).OrderBy<DiscoveredMod, string>((DiscoveredMod m) => m.ModId, StringComparer.Ordinal))
			{
				stringBuilder.Append(item.ModId).Append(':').Append(item.Version)
					.Append(':')
					.Append(item.ContentHash)
					.Append(';');
			}
			using SHA256 sHA = SHA256.Create();
			string text = BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(stringBuilder.ToString()))).Replace("-", "");
			return text.Substring(0, 4) + "-" + text.Substring(4, 4);
		}

		private Content ContentOf(string modId)
		{
			if (_content.TryGetValue(modId, out var value))
			{
				return value;
			}
			value = new Content();
			try
			{
				bool flag = modId == "base-game";
				foreach (ModContent.PerkEntry item in flag ? ModContent.VanillaPerks() : ModContent.PerksOf(modId))
				{
					value.Perks.Add(new KeyValuePair<string, Sprite>(item.Title, item.Icon));
					if ((Object)(object)item.Perk != (Object)null)
					{
						value.Cards.Add(new TierEditor.Entry
						{
							Key = ((Object)item.Perk).name,
							Title = item.Title,
							Icon = item.Icon
						});
					}
				}
				foreach (Item item2 in flag ? ModContent.VanillaItems() : ModContent.ItemsOf(modId))
				{
					value.Items.Add(new KeyValuePair<string, Sprite>(flag ? ModContent.PrettyBase(((Object)item2).name) : ModContent.Pretty(((Object)item2).name.Substring(modId.Length + 1)), item2.icon));
				}
			}
			catch (Exception ex)
			{
				Kit.Warn("content scan: " + ex.Message);
			}
			_content[modId] = value;
			return value;
		}

		private static string Short(string hash)
		{
			if (!string.IsNullOrEmpty(hash))
			{
				return hash.Substring(0, Math.Min(12, hash.Length));
			}
			return "-";
		}

		private static void OpenFolder(string path)
		{
			try
			{
				Process.Start("explorer.exe", "\"" + path + "\"");
			}
			catch (Exception ex)
			{
				Kit.Warn("open folder: " + ex.Message);
			}
		}

		private static void Status(DiscoveredMod m, out string status, out Color col)
		{
			//IL_003c: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			bool flag = Pending.Desired(m);
			if (Pending.IsQueued(m))
			{
				status = (flag ? "ON AFTER RESTART" : "OFF AFTER RESTART");
				col = WarnTxt;
			}
			else if (!m.IsValid)
			{
				status = "BROKEN";
				col = Ui.Bad;
			}
			else if (IsLoaded(m))
			{
				status = "RUNNING";
				col = GoodTxt;
			}
			else if (m.IsEnabled)
			{
				status = "FAILED";
				col = Ui.Bad;
			}
			else
			{
				status = "OFF";
				col = Ui.Muted;
			}
		}

		private void BuildList()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			Ui.Clear((Transform)(object)_listContent);
			_rows.Clear();
			AddBaseRow();
			foreach (DiscoveredMod mod in _mods)
			{
				AddRow(mod);
			}
			if (_mods.Count == 0)
			{
				Ui.Text((Transform)(object)_listContent, "No mods found.", 28f, Ui.Muted, (TextAlignmentOptions)513);
			}
			_listScroll.verticalNormalizedPosition = 1f;
			RefreshRows();
		}

		private void AddBaseRow()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00d6: Expected O, but got Unknown
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			//IL_0148: 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)
			Image val = Ui.Card((Transform)(object)_listContent, "Mod base-game", Ui.RowBg);
			RectTransform val2 = (RectTransform)((Transform)((Graphic)val).rectTransform).parent;
			Ui.Size(((Component)val2).gameObject, -1f, 104f);
			Transform val3 = ((Transform)val2).Find("Edge");
			_baseEdge = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<Image>() : null);
			Button obj = ((Component)val).gameObject.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)val;
			ColorBlock colors = ((Selectable)obj).colors;
			((ColorBlock)(ref colors)).highlightedColor = new Color(1.04f, 1.04f, 1.04f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.9f, 0.9f, 0.9f);
			((Selectable)obj).colors = colors;
			((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
			{
				Select("base-game");
			});
			((HorizontalOrVerticalLayoutGroup)Ui.HGroup(((Component)val).gameObject, 18f, new RectOffset(20, 20, 10, 10), (TextAnchor)3)).childForceExpandHeight = false;
			RectTransform obj2 = Ui.Node("Texts", (Transform)(object)((Graphic)val).rectTransform);
			Ui.VGroup(((Component)obj2).gameObject, 2f, null, (TextAnchor)3);
			Ui.Size(((Component)obj2).gameObject, -1f, -1f, 1f, 0f);
			Ui.Size(((Component)Ui.Text((Transform)(object)obj2, "Base Game", 33f, Ui.Dark, (TextAlignmentOptions)513)).gameObject, -1f, 42f);
			Ui.Size(((Component)Ui.Text((Transform)(object)obj2, "The game's own weapons and perks", 22f, Ui.Muted, (TextAlignmentOptions)513)).gameObject, -1f, 28f);
		}

		private void AddRow(DiscoveredMod m)
		{
			//IL_0057: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			ListRow listRow = new ListRow
			{
				Mod = m
			};
			bool flag = m.ModId == Kit.ModId;
			Image val = Ui.Card((Transform)(object)_listContent, "Mod " + m.ModId, Ui.RowBg);
			RectTransform val2 = (RectTransform)((Transform)((Graphic)val).rectTransform).parent;
			Ui.Size(((Component)val2).gameObject, -1f, 104f);
			listRow.Face = val;
			Transform val3 = ((Transform)val2).Find("Edge");
			listRow.Edge = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<Image>() : null);
			Button obj = ((Component)val).gameObject.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)val;
			ColorBlock colors = ((Selectable)obj).colors;
			((ColorBlock)(ref colors)).highlightedColor = new Color(1.04f, 1.04f, 1.04f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.9f, 0.9f, 0.9f);
			((Selectable)obj).colors = colors;
			string id = m.ModId;
			((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
			{
				Select(id);
			});
			((HorizontalOrVerticalLayoutGroup)Ui.HGroup(((Component)val).gameObject, 18f, new RectOffset(20, 20, 10, 10), (TextAnchor)3)).childForceExpandHeight = false;
			Action<bool> refresh;
			Button val4 = Ui.Checkbox((Transform)(object)((Graphic)val).rectTransform, Pending.Desired(m), delegate(bool on)
			{
				Pending.Set(m, on);
				_message = null;
				RefreshAll();
			}, out refresh, 54f);
			((Selectable)val4).interactable = !flag;
			listRow.Check = val4;
			listRow.RefreshCheck = refresh;
			RectTransform val5 = Ui.Node("Texts", (Transform)(object)((Graphic)val).rectTransform);
			Ui.VGroup(((Component)val5).gameObject, 2f, null, (TextAnchor)3);
			Ui.Size(((Component)val5).gameObject, -1f, -1f, 1f, 0f);
			listRow.Name = Ui.Text((Transform)(object)val5, m.Name ?? m.ModId, 33f, Ui.Dark, (TextAlignmentOptions)513);
			Ui.Size(((Component)listRow.Name).gameObject, -1f, 42f);
			listRow.Sub = Ui.Text((Transform)(object)val5, "", 22f, Ui.Muted, (TextAlignmentOptions)513);
			Ui.Size(((Component)listRow.Sub).gameObject, -1f, 28f);
			_rows[m.ModId] = listRow;
		}

		private void RefreshRows()
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			foreach (DiscoveredMod mod2 in _mods)
			{
				if (IsLoaded(mod2))
				{
					num++;
				}
			}
			((TMP_Text)_count).text = _mods.Count + " installed, " + num + " running";
			foreach (KeyValuePair<string, ListRow> row in _rows)
			{
				ListRow value = row.Value;
				DiscoveredMod mod = value.Mod;
				Status(mod, out var status, out var col);
				bool flag = Pending.Desired(mod);
				((Graphic)value.Name).color = (flag ? Ui.Dark : Ui.Muted);
				((TMP_Text)value.Sub).text = "v" + mod.Version + ((mod.ModId == Kit.ModId) ? "   (this menu)" : "") + "    " + status;
				((Graphic)value.Sub).color = col;
				value.RefreshCheck(flag);
				if ((Object)(object)value.Edge != (Object)null)
				{
					((Graphic)value.Edge).color = ((mod.ModId == _selected) ? Ui.Red : Ui.RowEdge);
				}
			}
			if ((Object)(object)_baseEdge != (Object)null)
			{
				((Graphic)_baseEdge).color = ((_selected == "base-game") ? Ui.Red : Ui.RowEdge);
			}
		}

		private void Select(string modId)
		{
			if (!(_selected == modId))
			{
				_selected = modId;
				_tab = 0;
				RefreshRows();
				RebuildDetails();
			}
		}

		public void Show(string modId, int tab)
		{
			_selected = modId;
			_tab = tab;
			RefreshRows();
			RefreshFooter();
			RebuildDetails();
		}

		public bool HasPerkTiers(string id)
		{
			return HasTiers(id);
		}

		public bool PreviewDrag(string key, int tier)
		{
			Canvas.ForceUpdateCanvases();
			if (_editor != null)
			{
				return _editor.PreviewDrag(key, tier);
			}
			return false;
		}

		public void ScrollDetails(float fromTop)
		{
			Canvas.ForceUpdateCanvases();
			_detailScroll.verticalNormalizedPosition = 1f - Mathf.Clamp01(fromTop);
		}

		private void RefreshAll()
		{
			RefreshRows();
			RefreshFooter();
			RebuildDetails();
		}

		private void RefreshFooter()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			bool flag = Pending.Count > 0;
			((Component)((Component)_undo).gameObject.transform.parent).gameObject.SetActive(flag);
			((Component)((Component)_apply).gameObject.transform.parent).gameObject.SetActive(flag);
			if (flag)
			{
				((Graphic)_footMsg).color = Ui.Gold;
				((TMP_Text)_footMsg).text = Pending.Count + " change" + ((Pending.Count == 1) ? "" : "s") + " pending. Applied when the game closes.";
			}
			else if (!string.IsNullOrEmpty(_message))
			{
				((Graphic)_footMsg).color = ErrTxt;
				((TMP_Text)_footMsg).text = _message;
			}
			else
			{
				((TMP_Text)_footMsg).text = "";
			}
		}

		private bool HasTiers(string id)
		{
			if (!PerkTiers.Available)
			{
				return false;
			}
			if (id == "base-game")
			{
				return ContentOf(id).Cards.Count > 0;
			}
			DiscoveredMod val = ((IEnumerable<DiscoveredMod>)_mods).FirstOrDefault((Func<DiscoveredMod, bool>)((DiscoveredMod x) => x.ModId == id));
			if (val != null && IsLoaded(val))
			{
				return ContentOf(id).Cards.Count > 0;
			}
			return false;
		}

		private static void ShowTab(Button b, bool on)
		{
			((Component)((Component)b).transform.parent).gameObject.SetActive(on);
		}

		private void RebuildDetails()
		{
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			Ui.Clear((Transform)(object)_detailContent);
			_detailScroll.verticalNormalizedPosition = 1f;
			_editor = null;
			bool flag = _selected == "base-game";
			DiscoveredMod val = (flag ? null : ((IEnumerable<DiscoveredMod>)_mods).FirstOrDefault((Func<DiscoveredMod, bool>)((DiscoveredMod x) => x.ModId == _selected)));
			if (val == null && !flag)
			{
				((TMP_Text)_title).text = "";
				((TMP_Text)_subtitle).text = "";
				_tabsRow.SetActive(false);
				return;
			}
			string text = (flag ? "base-game" : val.ModId);
			int num = Options.For(text).Count();
			bool flag2 = num > 0;
			bool flag3 = HasTiers(text);
			if (_tab == 1 && !flag2)
			{
				_tab = 0;
			}
			if (_tab == 2 && !flag3)
			{
				_tab = 0;
			}
			_tabsRow.SetActive(flag2 || flag3);
			ShowTab(_tabOptions, flag2);
			ShowTab(_tabRarity, flag3);
			Tab(_tabAbout, _tab == 0);
			Tab(_tabOptions, _tab == 1);
			Tab(_tabRarity, _tab == 2);
			if (flag2)
			{
				((Component)_tabOptions).GetComponentInChildren<TMP_Text>().text = (flag ? "WEAPONS (" : "OPTIONS (") + num + ")";
			}
			if (flag)
			{
				((TMP_Text)_title).text = "Base Game";
				((TMP_Text)_subtitle).text = "A Gentlemen's Dispute";
			}
			else
			{
				((TMP_Text)_title).text = val.Name ?? val.ModId;
				((TMP_Text)_subtitle).text = val.ModId + "    v" + val.Version;
			}
			if (_tab == 2)
			{
				BuildTiers(text);
				return;
			}
			if (_tab == 1)
			{
				BuildOptions(text);
				return;
			}
			if (flag)
			{
				BuildBaseAbout();
				return;
			}
			Status(val, out var status, out var col);
			BuildAbout(val, status, col);
		}

		private static void Tab(Button b, bool on)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			((Graphic)(Image)((Selectable)b).targetGraphic).color = (on ? Ui.Red : PillBg);
			((Graphic)((Component)b).GetComponentInChildren<TMP_Text>()).color = (on ? Ui.RedText : Ui.Dark);
		}

		private void Section(string title)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Ui.Size(((Component)Ui.Text((Transform)(object)_detailContent, title, 28f, Ui.Gold, (TextAlignmentOptions)513)).gameObject, -1f, 44f);
		}

		private TextMeshProUGUI Line(string s, float size, Color c)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return Ui.Text((Transform)(object)_detailContent, s, size, c, (TextAlignmentOptions)513, wrap: true);
		}

		private void BuildBaseAbout()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Line("The game's own weapons and perk cards. Use the tabs above to change how often each weapon shows up and which tier each perk card is in.", 25f, Ui.Dark);
			Content content = ContentOf("base-game");
			if (content.Items.Count > 0)
			{
				Section("WEAPONS (" + content.Items.Count + ")");
				Grid(content.Items);
			}
			if (content.Perks.Count > 0)
			{
				Section("PERKS (" + content.Perks.Count + ")");
				Grid(content.Perks);
			}
		}

		private void BuildTiers(string id)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			bool locked = PerkTiers.Locked;
			List<TierEditor.Entry> entries = ContentOf(id).Cards;
			RectTransform parent = Row((Transform)(object)_detailContent, 16f, 66f);
			Ui.Size(((Component)Ui.Text((Transform)(object)parent, locked ? "You are in someone else's lobby: the host's tiers decide the deal and can't be changed here." : "Drag a card onto a tier, or click a card and then a tier. Unsorted cards are dealt like Common. Your tiers apply when you host.", 21f, Ui.Muted, (TextAlignmentOptions)513, wrap: true)).gameObject, -1f, 66f, 1f, 0f);
			((Selectable)Ui.Pill((Transform)(object)parent, "RESET", PillBg, Ui.Dark, 200f, 56f, (UnityAction)delegate
			{
				foreach (TierEditor.Entry item in entries)
				{
					PerkTiers.Reset(item.Key);
				}
				RebuildDetails();
			})).interactable = !locked;
			_editor = new TierEditor((Transform)(object)_detailContent, entries, _dragLayer, _detailScroll);
		}

		private void BuildAbout(DiscoveredMod m, string status, Color col)
		{
			//IL_000d: 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)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			//IL_0167: 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)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			Ui.Size(((Component)Line(status, 30f, col)).gameObject, -1f, 40f);
			Line("Content hash  " + Short(m.ContentHash), 23f, Ui.Muted);
			Line(m.RootPath, 21f, Ui.Muted);
			if (!m.IsValid)
			{
				Line("Can't load: " + m.ValidationError, 25f, Ui.Bad);
			}
			else if (m.IsEnabled && !IsLoaded(m))
			{
				string lastLoadError = ModAssemblyLoader.LastLoadError;
				Line("Enabled but not running." + (string.IsNullOrEmpty(lastLoadError) ? "" : (" Last load error: " + lastLoadError)), 25f, Ui.Bad);
			}
			RectTransform parent = Row((Transform)(object)_detailContent, 12f, 70f);
			string path = m.RootPath;
			Ui.Pill((Transform)(object)parent, "OPEN FOLDER", PillBg, Ui.Dark, 300f, 62f, (UnityAction)delegate
			{
				OpenFolder(path);
			}, 28f);
			if (FriendPicker.Wanted(m.RootPath))
			{
				FriendPicker.Build(_detailContent, m.ModId);
			}
			if (!IsLoaded(m))
			{
				Line("Not running, so its content isn't listed.", 25f, Ui.Muted);
				return;
			}
			Content content = ContentOf(m.ModId);
			if (content.Items.Count == 0 && content.Perks.Count == 0)
			{
				Line("Adds no weapons or perks.", 25f, Ui.Muted);
				return;
			}
			if (content.Items.Count > 0)
			{
				Section("WEAPONS (" + content.Items.Count + ")");
				Grid(content.Items);
			}
			if (content.Perks.Count > 0)
			{
				Section("PERKS (" + content.Perks.Count + ")");
				Grid(content.Perks);
			}
		}

		private void Grid(List<KeyValuePair<string, Sprite>> entries)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = Ui.Node("Grid", (Transform)(object)_detailContent);
			GridLayoutGroup obj = ((Component)val).gameObject.AddComponent<GridLayoutGroup>();
			obj.cellSize = new Vector2(430f, 68f);
			obj.spacing = new Vector2(14f, 8f);
			obj.constraint = (Constraint)1;
			obj.constraintCount = 2;
			foreach (KeyValuePair<string, Sprite> entry in entries)
			{
				RectTransform obj2 = Ui.Node("Cell", (Transform)(object)val);
				((HorizontalOrVerticalLayoutGroup)Ui.HGroup(((Component)obj2).gameObject, 14f, null, (TextAnchor)3)).childForceExpandHeight = false;
				Ui.SpriteIcon((Transform)(object)obj2, entry.Value, 60f);
				Ui.Size(((Component)Ui.Text((Transform)(object)obj2, entry.Key, 27f, Ui.Dark, (TextAlignmentOptions)513)).gameObject, -1f, 60f, 1f, 0f);
			}
		}

		private void BuildOptions(string id)
		{
			//IL_002d: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			Line(Options.FromHost ? "You are in someone else's lobby: GAME options show the host's values and can't be changed here." : "GAME options are used when you host; in a friend's lobby their values win. LOCAL options only change your own game.", 22f, Ui.Muted);
			Ui.Pill((Transform)(object)Row((Transform)(object)_detailContent, 12f, 70f), "RESET ALL", PillBg, Ui.Dark, 260f, 62f, (UnityAction)delegate
			{
				Options.ResetMod(id);
				RebuildDetails();
			}, 28f);
			string text = null;
			foreach (OptionDef item in Options.For(id))
			{
				if (item.Group != text && !string.IsNullOrEmpty(item.Group))
				{
					Section(item.Group.ToUpperInvariant());
					if (!string.IsNullOrEmpty(item.GroupNote))
					{
						Line(item.GroupNote, 21f, Ui.Muted);
					}
				}
				text = item.Group;
				if (item.Rarity != RarityKind.None)
				{
					AddRarity(item);
				}
				else
				{
					AddOption(item);
				}
			}
		}

		private static string ShowNum(OptionDef d, double v)
		{
			if (d.Rarity != RarityKind.None && v <= 0.0)
			{
				return "never";
			}
			bool flag = d.Step >= 1.0 && Math.Abs(d.Step - Math.Round(d.Step)) < 1E-09;
			return d.Prefix + v.ToString(flag ? "0" : "0.##", CultureInfo.InvariantCulture) + d.Suffix;
		}

		private void AddRarity(OptionDef d)
		{
			//IL_0043: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			bool locked = Options.FromHost && d.Host;
			Image val = Ui.Card((Transform)(object)_detailContent, "Rarity " + d.Id, Ui.RowBg);
			Ui.Size(((Component)(RectTransform)((Transform)((Graphic)val).rectTransform).parent).gameObject, -1f, 84f);
			((HorizontalOrVerticalLayoutGroup)Ui.HGroup(((Component)val).gameObject, 18f, new RectOffset(20, 24, 8, 8), (TextAnchor)3)).childForceExpandHeight = false;
			Ui.SpriteIcon((Transform)(object)((Graphic)val).rectTransform, d.Icon, 60f);
			Ui.Size(((Component)Ui.Text((Transform)(object)((Graphic)val).rectTransform, d.Label, 29f, Ui.Dark, (TextAlignmentOptions)513)).gameObject, -1f, 44f, 1f, 0f);
			TextMeshProUGUI val2 = Ui.Text((Transform)(object)((Graphic)val).rectTransform, "", 29f, Ui.Dark, (TextAlignmentOptions)516);
			Action show = delegate
			{
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				((TMP_Text)val2).text = ShowNum(d, Options.Num(d, locked));
				((Graphic)val2).color = ((locked ? (Options.Effective(d) == d.DefaultText) : Options.IsDefault(d)) ? Ui.Dark : WarnTxt);
			};
			((Selectable)Ui.MakeSlider((Transform)(object)((Graphic)val).rectTransform, (float)d.Min, (float)d.Max, (float)d.Step, (float)Options.Num(d, locked), delegate(float v)
			{
				Options.SetOwn(d, OptionDef.Fmt(v));
				show();
			}, 280f)).interactable = !locked;
			Ui.Size(((Component)val2).gameObject, 110f, 44f);
			show();
		}

		private void AddOption(OptionDef d)
		{
			//IL_0043: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Unknown result type (might be due to invalid IL or missing references)
			//IL_0416: Expected O, but got Unknown
			bool locked = Options.FromHost && d.Host;
			Image val = Ui.Card((Transform)(object)_detailContent, "Opt " + d.Id, Ui.RowBg);
			Ui.Size(((Component)(RectTransform)((Transform)((Graphic)val).rectTransform).parent).gameObject, -1f, 96f);
			((HorizontalOrVerticalLayoutGroup)Ui.HGroup(((Component)val).gameObject, 22f, new RectOffset(24, 24, 12, 12), (TextAnchor)3)).childForceExpandHeight = false;
			RectTransform val2 = Ui.Node("Text", (Transform)(object)((Graphic)val).rectTransform);
			Ui.VGroup(((Component)val2).gameObject, 2f, null, (TextAnchor)3);
			Ui.Size(((Component)val2).gameObject, -1f, -1f, 1f, 0f);
			RectTransform parent = Row((Transform)(object)val2, 14f, 40f);
			Ui.Size(((Component)Ui.Text((Transform)(object)parent, d.Label, 31f, Ui.Dark, (TextAlignmentOptions)513)).gameObject, -1f, 40f);
			Ui.Size(((Component)Ui.Text((Transform)(object)parent, d.Host ? "GAME" : "LOCAL", 20f, d.Host ? WarnTxt : GoodTxt, (TextAlignmentOptions)513)).gameObject, -1f, 40f);
			if (!string.IsNullOrEmpty(d.Info))
			{
				Ui.Text((Transform)(object)val2, d.Info, 21f, Ui.Muted, (TextAlignmentOptions)513, wrap: true);
			}
			if (locked)
			{
				Ui.Text((Transform)(object)val2, "Host's value: " + Pretty(d, Options.Effective(d)), 21f, WarnTxt, (TextAlignmentOptions)513, wrap: true);
			}
			RectTransform val3 = Ui.Node("Control", (Transform)(object)((Graphic)val).rectTransform);
			((HorizontalOrVerticalLayoutGroup)Ui.HGroup(((Component)val3).gameObject, 16f, null, (TextAnchor)5)).childForceExpandHeight = false;
			if (d.Kind == OptKind.Number)
			{
				TextMeshProUGUI val4 = Ui.Text((Transform)(object)val3, "", 30f, Ui.Dark, (TextAlignmentOptions)516);
				Ui.Size(((Component)val4).gameObject, 100f, 44f);
				Action show = delegate
				{
					//IL_008b: 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)
					double v = Options.Num(d, locked);
					((TMP_Text)val4).text = ShowNum(d, v);
					((Graphic)val4).color = ((locked ? (Options.Effective(d) == d.DefaultText) : Options.IsDefault(d)) ? Ui.Dark : WarnTxt);
				};
				((Selectable)Ui.MakeSlider((Transform)(object)val3, (float)d.Min, (float)d.Max, (float)d.Step, (float)Options.Num(d, locked), delegate(float v)
				{
					Options.SetOwn(d, OptionDef.Fmt(v));
					show();
				}, 240f)).interactable = !locked;
				((TMP_Text)val4).transform.SetAsLastSibling();
				show();
			}
			else if (d.Kind == OptKind.Toggle)
			{
				((Selectable)Ui.Checkbox((Transform)(object)val3, (locked ? Options.Effective(d) : Options.Own(d)) == "true", delegate(bool on)
				{
					Options.SetOwn(d, on ? "true" : "false");
				}, out var _, 54f)).interactable = !locked;
			}
			else
			{
				Button pill = null;
				Func<string> cur = () => (!locked) ? Options.Own(d) : Options.Effective(d);
				pill = Ui.Pill((Transform)(object)val3, cur(), PillBg, Ui.Dark, 320f, 62f, (UnityAction)delegate
				{
					int num = Array.IndexOf(d.Choices, Options.Own(d));
					Options.SetOwn(d, d.Choices[(num + 1) % d.Choices.Length]);
					((Component)pill).GetComponentInChildren<TMP_Text>().text = cur();
				}, 28f);
				((Selectable)pill).interactable = !locked;
			}
		}

		private static string Pretty(OptionDef d, string v)
		{
			if (d.Kind == OptKind.Toggle)
			{
				if (!(v == "true"))
				{
					return "off";
				}
				return "on";
			}
			if (d.Kind == OptKind.Number)
			{
				if (!double.TryParse(v, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					return v;
				}
				return ShowNum(d, result);
			}
			return v;
		}

		private void ApplyAndQuit()
		{
			List<string> list = Pending.Apply();
			if (list.Count > 0)
			{
				_message = "Couldn't save: " + string.Join("; ", list.ToArray()) + " The game's Mods folder may be read-only; edit \"enabled\" in mod.json by hand.";
				RefreshFooter();
			}
			else
			{
				Options.Save();
				Application.Quit();
			}
		}
	}
	internal enum OptKind
	{
		Number,
		Toggle,
		Choice
	}
	internal class OptionDef
	{
		public string ModId;

		public string Id;

		public string Label;

		public string Info;

		public string Group;

		public OptKind Kind;

		public double Min;

		public double Max = 1.0;

		public double Step;

		public double Default;

		public bool DefaultOn;

		public string[] Choices = new string[0];

		public int DefaultIndex;

		public bool Host = true;

		public string Item;

		public string Field;

		public bool Multiply;

		public string Prefix = "";

		public string Suffix = "";

		public string GroupNote;

		public RarityKind Rarity;

		public Sprite Icon;

		private string _key;

		public string Key => _key ?? (_key = ModId + "." + Id);

		public string DefaultText
		{
			get
			{
				if (Kind == OptKind.Toggle)
				{
					if (!DefaultOn)
					{
						return "false";
					}
					return "true";
				}
				if (Kind == OptKind.Choice)
				{
					if (Choices.Length == 0)
					{
						return "";
					}
					return Choices[Math.Min(DefaultIndex, Choices.Length - 1)];
				}
				return Fmt(Default);
			}
		}

		public static string Fmt(double v)
		{
			return v.ToString("0.####", CultureInfo.InvariantCulture);
		}
	}
	internal static class Options
	{
		private static readonly List<OptionDef> _defs = new List<OptionDef>();

		private static readonly Dictionary<string, string> _local = new Dictionary<string, string>(StringComparer.Ordinal);

		private static Dictionary<string, string> _remote;

		private static readonly Dictionary<string, string> _effective = new Dictionary<string, string>(StringComparer.Ordinal);

		private static int _version;

		private static bool _loaded;

		private static bool _dirty;

		private static float _saveAt;

		public static bool Dry;

		public static List<OptionDef> Defs => _defs;

		public static bool FromHost => _remote != null;

		public static int Version => _version;

		private static string FilePath => Path.Combine(Kit.DataDir, "options.json");

		public static IEnumerable<OptionDef> For(string modId)
		{
			return _defs.Where((OptionDef d) => d.ModId == modId);
		}

		public static void Load()
		{
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Invalid comparison between Unknown and I4
			_defs.Clear();
			foreach (DiscoveredMod m in LocalModProvider.Mods ?? new List<DiscoveredMod>())
			{
				if (m == null || string.IsNullOrEmpty(m.ModId) || !m.IsValid || !m.IsEnabled)
				{
					continue;
				}
				string text = Path.Combine(m.RootPath, "options.json");
				bool rarity = true;
				if (File.Exists(text))
				{
					try
					{
						ParseFile(m.ModId, text, out rarity);
					}
					catch (Exception ex)
					{
						Kit.Warn("options.json of " + m.ModId + ": " + ex.Message);
					}
				}
				if (rarity)
				{
					Kit.Try("rarity of " + m.ModId, delegate
					{
						Rarity.AddFor(m.ModId, _defs);
					});
				}
			}
			Kit.Try("rarity of the base game", delegate
			{
				Rarity.AddBase(_defs);
			});
			_local.Clear();
			try
			{
				if (File.Exists(FilePath))
				{
					foreach (JProperty item in JObject.Parse(File.ReadAllText(FilePath)).Properties())
					{
						_local[item.Name] = (((int)item.Value.Type == 9) ? (((bool)item.Value) ? "true" : "false") : Convert.ToString(item.Value, CultureInfo.InvariantCulture));
					}
				}
			}
			catch (Exception ex2)
			{
				Kit.Warn("saved options unreadable, using defaults: " + ex2.Message);
			}
			_loaded = true;
			Publish(all: true);
			Kit.Log(_defs.Count + " option(s) from " + _defs.Select((OptionDef d) => d.ModId).Distinct().Count() + " mod(s)");
		}

		private static void ParseFile(string modId, string file, out bool rarity)
		{
			JObject val = JObject.Parse(File.ReadAllText(file));
			rarity = val["rarity"] == null || (bool)val["rarity"];
			JToken obj = val["options"];
			JArray val2 = (JArray)(object)((obj is JArray) ? obj : null);
			if (val2 == null)
			{
				return;
			}
			foreach (JObject item in ((IEnumerable)val2).OfType<JObject>())
			{
				OptionDef d = new OptionDef
				{
					ModId = modId
				};
				d.Id = (string)item["id"];
				if (string.IsNullOrEmpty(d.Id) || _defs.Any((OptionDef x) => x.Key == modId + "." + d.Id))
				{
					Kit.Warn(modId + ": option without a unique id skipped");
					continue;
				}
				d.Label = ((string)item["label"]) ?? d.Id;
				d.Info = (string)item["info"];
				d.Group = ((string)item["group"]) ?? "";
				d.Suffix = ((string)item["unit"]) ?? "";
				d.Host = (((string)item["scope"]) ?? "game") != "local";
				switch ((((string)item["type"]) ?? "number").ToLowerInvariant())
				{
				case "toggle":
				case "bool":
					d.Kind = OptKind.Toggle;
					d.DefaultOn = item["default"] != null && (bool)item["default"];
					break;
				case "choice":
				{
					d.Kind = OptKind.Choice;
					JToken obj2 = item["choices"];
					JArray val3 = (JArray)(object)((obj2 is JArray) ? obj2 : null);
					d.Choices = ((val3 != null) ? ((IEnumerable<JToken>)val3).Select((JToken c) => (string)c).ToArray() : new string[0]);
					if (d.Choices.Length == 0)
					{
						Kit.Warn(modId + "." + d.Id + ": choice without choices skipped");
						continue;
					}
					string value = (string)item["default"];
					d.DefaultIndex = Math.Max(0, Array.IndexOf(d.Choices, value));
					break;
				}
				default:
					d.Kind = OptKind.Number;
					d.Min = ((item["min"] != null) ? ((double)item["min"]) : 0.0);
					d.Max = ((item["max"] != null) ? ((double)item["max"]) : 1.0);
					d.Step = ((item["step"] != null) ? ((double)item["step"]) : 0.0);
					d.Default = ((item["default"] != null) ? ((double)item["default"]) : d.Min);
					break;
				}
				string text = (string)item["set"];
				if (!string.IsNullOrEmpty(text))
				{
					d.Item = (string)item["item"];
					d.Field = text;
					d.Multiply = (((string)item["mode"]) ?? "set").ToLowerInvariant() == "multiply";
					if (string.IsNullOrEmpty(d.Item) || text.IndexOf('.') < 1 || d.Kind == OptKind.Choice)
					{
						Kit.Warn(modId + "." + d.Id + ": a stat hook needs \"item\", \"set\":\"Component.field\" and a number or toggle");
						d.Item = null;
						d.Field = null;
					}
				}
				_defs.Add(d);
			}
		}

		public static string Own(OptionDef d)
		{
			if (!_local.TryGetValue(d.Key, out var value))
			{
				return d.DefaultText;
			}
			return Clean(d, value);
		}

		public static string Effective(OptionDef d)
		{
			if (!_effective.TryGetValue(d.Key, out var value))
			{
				return d.DefaultText;
			}
			return value;
		}

		public static bool IsDefault(OptionDef d)
		{
			return Own(d) == d.DefaultText;
		}

		private static string Clean(OptionDef d, string raw)
		{
			if (d.Kind == OptKind.Toggle)
			{
				if (!(raw == "true"))
				{
					return "false";
				}
				return "true";
			}
			if (d.Kind == OptKind.Choice)
			{
				if (!d.Choices.Contains(raw))
				{
					return d.DefaultText;
				}
				return raw;
			}
			if (!double.TryParse(raw, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return d.DefaultText;
			}
			if (d.Step > 0.0)
			{
				result = d.Min + Math.Round((result - d.Min) / d.Step) * d.Step;
			}
			return OptionDef.Fmt(Math.Max(d.Min, Math.Min(d.Max, result)));
		}

		public static double Num(OptionDef d, bool effective = false)
		{
			if (!double.TryParse(effective ? Effective(d) : Own(d), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return d.Default;
			}
			return result;
		}

		public static void SetOwn(OptionDef d, string value)
		{
			value = Clean(d, value);
			if (value == d.DefaultText)
			{
				_local.Remove(d.Key);
			}
			else
			{
				_local[d.Key] = value;
			}
			_dirty = true;
			_saveAt = Time.realtimeSinceStartup + 0.6f;
			Publish(all: false);
		}

		public static void ResetMod(string modId)
		{
			foreach (OptionDef item in For(modId))
			{
				if (!FromHost || !item.Host)
				{
					_local.Remove(item.Key);
				}
			}
			_dirty = true;
			_saveAt = Time.realtimeSinceStartup + 0.2f;
			Publish(all: false);
		}

		public static Dictionary<string, string> HostValues()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			foreach (OptionDef def in _defs)
			{
				if (def.Host)
				{
					string text = Own(def);
					if (text != def.DefaultText)
					{
						dictionary[def.Key] = text;
					}
				}
			}
			return dictionary;
		}

		public static void SetRemote(Dictionary<string, string> map)
		{
			if ((map != null || _remote != null) && (map == null || _remote == null || map.Count != _remote.Count || !map.All((KeyValuePair<string, string> kv) => _remote.TryGetValue(kv.Key, out var value) && value == kv.Value)))
			{
				_remote = map;
				Kit.Log((map == null) ? "left the host's lobby, using my own option values" : ("using the host's option values (" + map.Count + ")"));
				Publish(all: false);
			}
		}

		private static void Publish(bool all)
		{
			List<OptionDef> list = new List<OptionDef>();
			foreach (OptionDef def in _defs)
			{
				string text = Own(def);
				if (def.Host && _remote != null)
				{
					text = (_remote.TryGetValue(def.Key, out var value) ? Clean(def, value) : def.DefaultText);
				}
				string value2;
				bool num = _effective.TryGetValue(def.Key, out value2);
				_effective[def.Key] = text;
				if (!num || value2 != text)
				{
					list.Add(def);
				}
			}
			if (_effective.Count > _defs.Count)
			{
				HashSet<string> live = new HashSet<string>(_defs.Select((OptionDef optionDef) => optionDef.Key), StringComparer.Ordinal);
				foreach (string item in _effective.Keys.Where((string k) => !live.Contains(k)).ToList())
				{
					_effective.Remove(item);
				}
			}
			AppDomain.CurrentDomain.SetData("agd.options", _effective);
			if (list.Count > 0)
			{
				_version++;
				AppDomain.CurrentDomain.SetData("agd.options.v", _version);
			}
			foreach (OptionDef d in list)
			{
				if (d.Item != null && (!all || !(Effective(d) == d.DefaultText)))
				{
					Kit.Try("stat hook " + d.Key, delegate
					{
						StatHook.Apply(d, Effective(d));
					});
				}
			}
		}

		public static void Unload()
		{
			Kit.Try("stat hook restore", delegate
			{
				StatHook.RestoreAll();
			});
			if (_dirty)
			{
				Save();
			}
			_effective.Clear();
			_defs.Clear();
			_remote = null;
			_loaded = false;
			AppDomain.CurrentDomain.SetData("agd.options", null);
			AppDomain.CurrentDomain.SetData("agd.options.v", null);
		}

		public static void Tick()
		{
			if (_dirty && Time.realtimeSinceStartup >= _saveAt)
			{
				Save();
			}
		}

		public static void Save()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			_dirty = false;
			if (Dry || !_loaded)
			{
				return;
			}
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
				JObject val = new JObject();
				foreach (KeyValuePair<string, string> item in _local.OrderBy<KeyValuePair<string, string>, string>((KeyValuePair<string, string> k) => k.Key, StringComparer.Ordinal))
				{
					val[item.Key] = JToken.op_Implicit(item.Value);
				}
				File.WriteAllText(FilePath, ((object)val).ToString());
			}
			catch (Exception ex)
			{
				Kit.Warn("could not save options: " + ex.Message);
			}
		}
	}
	internal static class StatHook
	{
		private class Captured
		{
			public object Target;

			public FieldInfo Field;

			public object Orig;
		}

		private static readonly Dictionary<string, Captured> _captured = new Dictionary<string, Captured>();

		public static void Apply(OptionDef d, string value)
		{
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			Item val = FindItem(d);
			if ((Object)(object)val == (Object)null)
			{
				Kit.Warn("option " + d.Key + ": item '" + d.Item + "' not found");
				return;
			}
			int num = d.Field.IndexOf('.');
			string comp = d.Field.Substring(0, num);
			string text = d.Field.Substring(num + 1);
			object v = ((d.Kind == OptKind.Toggle) ? ((object)(value == "true")) : ((object)double.Parse(value, CultureInfo.InvariantCulture)));
			if (comp == "Item")
			{
				Report(d, ((Object)val).name + ".Item." + text, Set(val, text, v, d.Multiply, double.NaN));
				return;
			}
			if ((Object)(object)val.prefab == (Object)null)
			{
				Kit.Warn("option " + d.Key + ": " + ((Object)val).name + " has no prefab");
				return;
			}
			Component val2 = ((IEnumerable<Component>)val.prefab.GetComponentsInChildren<Component>(true)).FirstOrDefault((Func<Component, bool>)((Component c) => (Object)(object)c != (Object)null && ((object)c).GetType().Name == comp));
			if ((Object)(object)val2 == (Object)null)
			{
				Kit.Warn("option " + d.Key + ": " + ((Object)val).name + " has no component " + comp);
				return;
			}
			string text2 = Set(val2, text, v, d.Multiply, double.NaN);
			double baseValue = (d.Multiply ? OrigOf(val2, text) : double.NaN);
			int num2 = 0;
			foreach (Component item in Resources.FindObjectsOfTypeAll(((object)val2).GetType()).Cast<Component>())
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)val2))
				{
					Scene scene = item.gameObject.scene;
					if (((Scene)(ref scene)).IsValid() && IsInstanceOf(((Object)item.gameObject).name, ((Object)val.prefab).name))
					{
						Set(item, text, v, d.Multiply, baseValue);
						num2++;
					}
				}
			}
			Report(d, ((Object)val).name + "." + comp + "." + text, text2 + ((num2 > 0) ? (" (+" + num2 + " live)") : ""));
		}

		private static void Report(OptionDef d, string target, string result)
		{
			string msg = "stat " + d.Key + " -> " + target + ": " + result;
			if (result.StartsWith("no field", StringComparison.Ordinal))
			{
				Kit.Warn(msg);
			}
			else
			{
				Kit.Log(msg);
			}
		}

		private static Item FindItem(OptionDef d)
		{
			if ((Object)(object)Kit.Design == (Object)null)
			{
				return null;
			}
			if (d.ModId == "base-game")
			{
				return ((IEnumerable<Item>)Kit.Design.itemList).FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && string.Equals(((Object)i).name, d.Item, StringComparison.Ordinal)));
			}
			string full = (d.Item.StartsWith(d.ModId + "_", StringComparison.OrdinalIgnoreCase) ? d.Item : (d.ModId + "_" + d.Item));
			return ((IEnumerable<Item>)Kit.Design.itemList).FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && string.Equals(((Object)i).name, full, StringComparison.OrdinalIgnoreCase)));
		}

		private static bool IsInstanceOf(string instance, string prefab)
		{
			if (!instance.StartsWith(prefab, StringComparison.Ordinal))
			{
				return false;
			}
			if (instance.Length == prefab.Length)
			{
				return true;
			}
			char c = instance[prefab.Length];
			if (c != '(')
			{
				return c == ' ';
			}
			return true;
		}

		private static FieldInfo FindField(object target, string field)
		{
			FieldInfo fieldInfo = null;
			Type type = target.GetType();
			while (fieldInfo == null && type != null)
			{
				fieldInfo = type.GetField(field, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				type = type.BaseType;
			}
			return fieldInfo;
		}

		private static string KeyOf(object target, FieldInfo f)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return ((Object)target).GetInstanceID() + "." + f.Name;
		}

		private static double OrigOf(object target, string field)
		{
			FieldInfo fieldInfo = FindField(target, field);
			if (!(fieldInfo != null) || !_captured.TryGetValue(KeyOf(target, fieldInfo), out var value))
			{
				return double.NaN;
			}
			return Convert.ToDouble(value.Orig, CultureInfo.InvariantCulture);
		}

		private static string Set(object target, string field, object v, bool multiply, double baseValue)
		{
			FieldInfo fieldInfo = FindField(target, field);
			if (fieldInfo == null)
			{
				return "no field " + target.GetType().Name + "." + field;
			}
			object value = fieldInfo.GetValue(target);
			string key = KeyOf(target, fieldInfo);
			if (!_captured.ContainsKey(key))
			{
				_captured[key] = new Captured
				{
					Target = target,
					Field = fieldInfo,
					Orig = value
				};
			}
			if (multiply)
			{
				v = (double.IsNaN(baseValue) ? Convert.ToDouble(_captured[key].Orig, CultureInfo.InvariantCulture) : baseValue) * Convert.ToDouble(v, CultureInfo.InvariantCulture);
			}
			object value2 = ((fieldInfo.FieldType == typeof(bool)) ? ((object)Convert.ToBoolean(v)) : Convert.ChangeType(v, fieldInfo.FieldType, CultureInfo.InvariantCulture));
			fieldInfo.SetValue(target, value2);
			return value?.ToString() + " -> " + fieldInfo.GetValue(target);
		}

		public static void RestoreAll()
		{
			foreach (Captured value in _captured.Values)
			{
				object target = value.Target;
				if (!((Object)((target is Object) ? target : null) == (Object)null))
				{
					value.Field.SetValue(value.Target, value.Orig);
				}
			}
			_captured.Clear();
		}
	}
	public struct OptionsSync : IBroadcast
	{
		public string Blob;
	}
	internal static class OptionsNet
	{
		private static bool _serializers;

		private static bool _client;

		private static NetworkManager _nm;

		private static string _sent;

		private static int _clients = -1;

		private static float _next;

		private static float _resend;

		public static void Poll()
		{
			if (!_serializers)
			{
				_serializers = true;
				GenericWriter<OptionsSync>.SetWrite((Action<Writer, OptionsSync>)delegate(Writer w, OptionsSync v)
				{
					w.WriteString(v.Blob ?? "");
				});
				GenericReader<OptionsSync>.SetRead((Func<Reader, OptionsSync>)delegate(Reader r)
				{
					OptionsSync result = default(OptionsSync);
					result.Blob = r.ReadString();
					return result;
				});
			}
			NetworkManager networkManager = InstanceFinder.NetworkManager;
			if ((Object)(object)networkManager != (Object)(object)_nm)
			{
				bool num = (Object)(object)_nm != (Object)null;
				Forget();
				_nm = networkManager;
				if (num)
				{
					Options.SetRemote(null);
				}
			}
			if ((Object)(object)networkManager == (Object)null)
			{
				return;
			}
			if (!networkManager.IsClientStarted || networkManager.IsServerStarted)
			{
				if (_client)
				{
					_client = false;
					try
					{
						networkManager.ClientManager.UnregisterBroadcast<OptionsSync>((Action<OptionsSync, Channel>)ClientGot);
					}
					catch (Exception)
					{
					}
					Options.SetRemote(null);
				}
			}
			else if (!_client)
			{
				_client = true;
				try
				{
					networkManager.ClientManager.UnregisterBroadcast<OptionsSync>((Action<OptionsSync, Channel>)ClientGot);
				}
				catch (Exception)
				{
				}
				networkManager.ClientManager.RegisterBroadcast<OptionsSync>((Action<OptionsSync, Channel>)ClientGot);
				Options.SetRemote(new Dictionary<string, string>());
			}
			if (!networkManager.IsServerStarted)
			{
				_sent = null;
				_clients = -1;
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime < _next)
			{
				return;
			}
			_next = unscaledTime + 0.5f;
			int count = networkManager.ServerManager.Clients.Count;
			if (count <= 1)
			{
				_sent = null;
				_clients = count;
				return;
			}
			string text = Encode(Options.HostValues());
			if (text == _sent && count == _clients && unscaledTime < _resend)
			{
				return;
			}
			_resend = unscaledTime + 3f;
			try
			{
				networkManager.ServerManager.Broadcast<OptionsSync>(new OptionsSync
				{
					Blob = text
				}, true, (Channel)0);
				_sent = text;
				_clients = count;
			}
			catch (Exception ex3)
			{
				Kit.Warn("options: broadcast failed: " + ex3.Message);
			}
		}

		public static void Unregister()
		{
			try
			{
				if ((Object)(object)_nm != (Object)null && _client)
				{
					_nm.ClientManager.UnregisterBroadcast<OptionsSync>((Action<OptionsSync, Channel>)ClientGot);
				}
			}
			catch (Exception)
			{
			}
			Forget();
			Options.SetRemote(null);
		}

		private static void Forget()
		{
			_client = false;
			_sent = null;
			_clients = -1;
			_resend = 0f;
			_nm = null;
		}

		private static void ClientGot(OptionsSync m, Channel ch)
		{
			NetworkManager networkManager = InstanceFinder.NetworkManager;
			if (!((Object)(object)networkManager != (Object)null) || !networkManager.IsServerStarted)
			{
				Options.SetRemote(Decode(m.Blob));
			}
		}

		private static string Encode(Dictionary<string, string> map)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<string, string> item in map)
			{
				stringBuilder.Append(item.Key).Append('=').Append(item.Value)
					.Append('\n');
			}
			return stringBuilder.ToString();
		}

		private static Dictionary<string, string> Decode(string blob)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			string[] array = (blob ?? "").Split('\n');
			foreach (string text in array)
			{
				int num = text.IndexOf('=');
				if (num > 0)
				{
					dictionary[text.Substring(0, num)] = text.Substring(num + 1);
				}
			}
			return dictionary;
		}
	}
	internal static class Pending
	{
		private static readonly Dictionary<string, bool> _map = new Dictionary<string, bool>(StringComparer.Ordinal);

		private const string Inserted = " \"enabled\": false,";

		private static readonly Regex EnabledKey = new Regex("(\"enabled\"\\s*:\\s*)(true|false)");

		public static bool Dry;

		private static string FilePath => Path.Combine(Kit.DataDir, "pending.txt");

		public static int Count => _map.Count;

		public static void Load()
		{
			_map.Clear();
			if (!File.Exists(FilePath))
			{
				return;
			}
			string[] array = File.ReadAllLines(FilePath);
			foreach (string text in array)
			{
				int num = text.IndexOf('=');
				if (num > 0)
				{
					_map[text.Substring(0, num).Trim()] = text.Substring(num + 1).Trim() == "true";
				}
			}
			foreach (string item in _map.Keys.ToList())
			{
				DiscoveredMod val = LocalModProvider.FindById(item);
				if (val == null || val.IsEnabled == _map[item])
				{
					_map.Remove(item);
				}
			}
			Save();
			if (_map.Count > 0)
			{
				Kit.Log(_map.Count + " queued change(s) carried over from last session");
			}
		}

		private static void Save()
		{
			if (Dry)
			{
				return;
			}
			if (_map.Count == 0)
			{
				if (File.Exists(FilePath))
				{
					File.Delete(FilePath);
				}
			}
			else
			{
				File.WriteAllLines(FilePath, _map.Select((KeyValuePair<string, bool> kv) => kv.Key + "=" + (kv.Value ? "true" : "false")).ToArray());
			}
		}

		public static bool Desired(DiscoveredMod m)
		{
			if (!_map.TryGetValue(m.ModId, out var value))
			{
				return m.IsEnabled;
			}
			return value;
		}

		public static bool IsQueued(DiscoveredMod m)
		{
			return _map.ContainsKey(m.ModId);
		}

		public static void Set(DiscoveredMod m, bool on)
		{
			if (on == m.IsEnabled)
			{
				_map.Remove(m.ModId);
			}
			else
			{
				_map[m.ModId] = on;
			}
			Save();
		}

		public static void Clear()
		{
			_map.Clear();
			Save();
		}

		public static List<string> Apply()
		{
			List<string> list = new List<string>();
			if (Dry || _map.Count == 0)
			{
				return list;
			}
			foreach (KeyValuePair<string, bool> item in _map.ToList())
			{
				DiscoveredMod val = LocalModProvider.FindById(item.Key);
				if (val == null)
				{
					_map.Remove(item.Key);
					continue;
				}
				try
				{
					WriteEnabled(Path.Combine(val.RootPath, "mod.json"), item.Value);
					_map.Remove(item.Key);
					Kit.Log((item.Value ? "enabled " : "disabled ") + val.ModId + " for the next launch");
				}
				catch (Exception ex)
				{
					list.Add(val.Name + ": " + ex.Message);
					Kit.Error("could not update " + val.ModId + ": " + ex.Message);
				}
			}
			Save();
			return list;
		}

		private static void WriteEnabled(string path, bool on)
		{
			byte[] array = File.ReadAllBytes(path);
			bool flag = array.Length >= 3 && array[0] == 239 && array[1] == 187 && array[2] == 191;
			int num = (flag ? 3 : 0);
			string text = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetString(array, num, array.Length - num);
			string text2;
			if (on && text.Contains(" \"enabled\": false,"))
			{
				text2 = text.Replace(" \"enabled\": false,", "");
			}
			else if (EnabledKey.IsMatch(text))
			{
				text2 = EnabledKey.Replace(text, "${1}" + (on ? "true" : "false"), 1);
			}
			else
			{
				if (on)
				{
					return;
				}
				int num2 = text.IndexOf('{');
				if (num2 < 0)
				{
					throw new InvalidDataException("mod.json is not a JSON object");
				}
				text2 = text.Insert(num2 + 1, " \"enabled\": false,");
			}
			if (text2 == text)
			{
				return;
			}
			byte[] bytes = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(text2);
			using FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
			if (flag)
			{
				fileStream.Write(new byte[3] { 239, 187, 191 }, 0, 3);
			}
			fileStream.Write(bytes, 0, bytes.Length);
		}
	}
	public class Plugin : IModPlugin
	{
		public void OnLoad(IModContext context)
		{
			Kit.Init(context);
			Kit.Try("pending", Pending.Load);
			Kit.Try("runner", delegate
			{
				Kit.Host.AddComponent<Runner>();
			});
			Kit.Log("loaded (MODS in the main menu)");
		}

		public void OnUnload()
		{
			Kit.Try("net", OptionsNet.Unregister);
			Kit.Try("menu", MenuHook.Uninstall);
			Kit.Try("options", Options.Unload);
			Kit.Shutdown();
		}
	}
	internal enum RarityKind
	{
		None,
		Item
	}
	internal static class ModContent
	{
		public class PerkEntry
		{
			public Perk Perk;

			public string Id;

			public string Title;

			public Sprite Icon;
		}

		private static readonly HashSet<string> Acronyms = new HashSet<string> { "smg", "lmg", "rpg", "ak", "tnt", "hp", "npc" };

		public static List<Item> ItemsOf(string modId)
		{
			List<Item> list = new List<Item>();
			if ((Object)(object)Kit.Design == (Object)null)
			{
				return list;
			}
			string value = modId + "_";
			foreach (Item item in Kit.Design.itemList)
			{
				if ((Object)(object)item != (Object)null && ((Object)item).name.StartsWith(value, StringComparison.Ordinal))
				{
					list.Add(item);
				}
			}
			return list;
		}

		public static List<PerkEntry> PerksOf(string modId)
		{
			List<PerkEntry> list = new List<PerkEntry>();
			RegisteredModPerk val = default(RegisteredModPerk);
			foreach (Perk modPerk in SessionContentRegistry.ModPerkList)
			{
				if (!((Object)(object)modPerk == (Object)null) && SessionContentRegistry.TryGetModRegistration(modPerk, ref val) && !(val.ModId != modId))
				{
					PerkEntry perkEntry = new PerkEntry
					{
						Perk = modPerk,
						Id = val.PerkId
					};
					perkEntry.Title = ((val.Metadata != null && !string.IsNullOrEmpty(val.Metadata.Title)) ? val.Metadata.Title : val.PerkId);
					try
					{
						perkEntry.Icon = PerkDisplay.GetIcon(modPerk);
					}
					catch (Exception)
					{
						perkEntry.Icon = modPerk.icon;
					}
					list.Add(perkEntry);
				}
			}
			return list;
		}

		public static List<Item> VanillaItems()
		{
			List<Item> list = new List<Item>();
			if ((Object)(object)Kit.Design == (Object)null)
			{
				return list;
			}
			List<string> list2 = new List<string>();
			foreach (DiscoveredMod item in LocalModProvider.Mods ?? new List<DiscoveredMod>())
			{
				if (item != null && !string.IsNullOrEmpty(item.ModId))
				{
					list2.Add(item.ModId + "_");
				}
			}
			foreach (Item item2 in Kit.Design.itemList)
			{
				if ((Object)(object)item2 == (Object)null)
				{
					continue;
				}
				bool flag = false;
				for (int i = 0; i < list2.Count; i++)
				{
					if (flag)
					{
						break;
					}
					flag = ((Object)item2).name.StartsWith(list2[i], StringComparison.Ordinal);
				}
				if (!flag)
				{
					list.Add(item2);
				}
			}
			return list;
		}

		public static List<PerkEntry> VanillaPerks()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			List<PerkEntry> list = new List<PerkEntry>();
			if ((Object)(object)Kit.Design == (Object)null || Kit.Design.perks == null)
			{
				return list;
			}
			Perk[] perks = Kit.Design.perks;
			foreach (Perk val in perks)
			{
				if (!((Object)(object)val == (Object)null) && !val.dontIncludeInPool && (int)val.availability != 3)
				{
					PerkEntry perkEntry = new PerkEntry
					{
						Perk = val,
						Id = ((Object)val).name
					};
					try
					{
						perkEntry.Title = PerkDisplay.GetTitle(val);
					}
					catch (Exception)
					{
					}
					if (string.IsNullOrEmpty(perkEntry.Title))
					{
						perkEntry.Title = PrettyBase(((Object)val).name);
					}
					try
					{
						perkEntry.Icon = PerkDisplay.GetIcon(val);
					}
					catch (Exception)
					{
						perkEntry.Icon = val.icon;
					}
					list.Add(perkEntry);
				}
			}
			return list;
		}

		public static string PrettyBase(string name)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < name.Length; i++)
			{
				char c = name[i];
				if (c == '_' || c == '-')
				{
					stringBuilder.Append(' ');
					continue;
				}
				if (i > 0 && char.IsUpper(c) && char.IsLower(name[i - 1]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(c);
			}
			return stringBuilder.ToString();
		}

		public static string Pretty(string id)
		{
			string[] source = id.Replace('-', '_').Split(new char[1] { '_' }, StringSplitOptions.RemoveEmptyEntries);
			return string.Join(" ", source.Select((string w) => (!Acronyms.Contains(w.ToLowerInvariant())) ? (char.ToUpperInvariant(w[0]) + w.Substring(1)) : w.ToUpperInvariant()).ToArray());
		}
	}
	internal static class Rarity
	{
		public const string ItemGroup = "Weapon spawn rate";

		public const string BaseId = "base-game";

		public static void AddBase(List<OptionDef> defs)
		{
			int count = defs.Count;
			foreach (Item item in ModContent.VanillaItems())
			{
				if (!(item.spawnChanceMultiplier <= 0f))
				{
					StringBuilder id = new StringBuilder("rarity_item_");
					string name = ((Object)item).name;
					foreach (char c in name)
					{
						id.Append(char.IsLetterOrDigit(c) ? c : '_');
					}
					if (!defs.Any((OptionDef x) => x.ModId == "base-game" && x.Id == id.ToString()))
					{
						defs.Add(new OptionDef
						{
							ModId = "base-game",
							Id = id.ToString(),
							Label = ModContent.PrettyBase(((Object)item).name),
							Group = "Weapon spawn rate",
							GroupNote = "How often each of the game's own weapons shows up on the pedestals. x1 = as the game ships it, x0 = never.",
							Kind = OptKind.Number,
							Min = 0.0,
							Max = 3.0,
							Step = 0.1,
							Default = 1.0,
							Host = true,
							Item = ((Object)item).name,
							Field = "Item.spawnChanceMultiplier",
							Multiply = true,
							Rarity = RarityKind.Item,
							Icon = item.icon,
							Prefix = "x"
						});
					}
				}
			}
			if (defs.Count > count)
			{
				Kit.Log("rarity: base game: " + (defs.Count - count) + " weapon(s)");
			}
		}

		public static void AddFor(string modId, List<OptionDef> defs)
		{
			int count = defs.Count;
			foreach (Item item in ModContent.ItemsOf(modId))
			{
				if (!(item.spawnChanceMultiplier <= 0f))
				{
					string text = ((Object)item).name.Substring(modId.Length + 1);
					string id = "rarity_item_" + text;
					if (!defs.Any((OptionDef x) => x.ModId == modId && x.Id == id))
					{
						defs.Add(new OptionDef
						{