Decompiled source of ModMenu v0.1.0

ModMenu.dll

Decompiled 3 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalCompanyInputUtils.Api;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.UI;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("ModMenuTest")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ModMenu")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+e03db308db5b2f5b1076eb9e188f6be649e3cbc4")]
[assembly: AssemblyProduct("ModMenu")]
[assembly: AssemblyTitle("ModMenu")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ModMenu
{
	internal class Menu : MonoBehaviour
	{
		internal class Row
		{
			public MenuApi.Entry Entry;

			public string Heading;

			public string Blocked;
		}

		internal static Menu Instance;

		internal string Tab;

		internal string Search = "";

		internal int Cursor;

		internal int Scroll;

		internal readonly List<Row> Rows = new List<Row>();

		internal const string FavTab = "Favourites";

		internal const int VisibleRows = 8;

		private Panel _panel;

		private int _builtVersion = -1;

		private float _nextRefresh;

		internal bool IsOpen { get; private set; }

		internal static PlayerControllerB Me
		{
			get
			{
				if (!((Object)(object)GameNetworkManager.Instance != (Object)null))
				{
					return null;
				}
				return GameNetworkManager.Instance.localPlayerController;
			}
		}

		private void Awake()
		{
			Instance = this;
		}

		internal static string CannotOpen()
		{
			PlayerControllerB me = Me;
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)me == (Object)null)
			{
				return "not in a game";
			}
			if (!me.isPlayerControlled || me.isPlayerDead)
			{
				return "not while dead";
			}
			if (me.inTerminalMenu)
			{
				return "not at the terminal";
			}
			if (me.isTypingChat)
			{
				return "not while typing";
			}
			if (me.inSpecialMenu)
			{
				return "not in another menu";
			}
			if ((Object)(object)me.quickMenuManager == (Object)null || me.quickMenuManager.isMenuOpen)
			{
				return "not in the pause menu";
			}
			return null;
		}

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

		internal bool Open()
		{
			if (IsOpen)
			{
				return true;
			}
			string text = CannotOpen();
			if (text != null)
			{
				Plugin.Log.LogInfo((object)("ModMenu: can't open (" + text + ")."));
				return false;
			}
			if ((Object)(object)_panel == (Object)null)
			{
				_panel = Panel.Create(this);
			}
			Me.quickMenuManager.isMenuOpen = true;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			if (Keyboard.current != null)
			{
				Keyboard.current.onTextInput += OnText;
			}
			IsOpen = true;
			List<string> list = TabList();
			Tab = (list.Contains(Plugin.LastTab.Value) ? Plugin.LastTab.Value : list.FirstOrDefault());
			Search = "";
			Cursor = 0;
			Scroll = 0;
			Rebuild();
			((Component)_panel).gameObject.SetActive(true);
			return true;
		}

		internal void Close(bool quickMenuClosed = false)
		{
			if (IsOpen)
			{
				IsOpen = false;
				if (Keyboard.current != null)
				{
					Keyboard.current.onTextInput -= OnText;
				}
				if ((Object)(object)_panel != (Object)null)
				{
					((Component)_panel).gameObject.SetActive(false);
				}
				PlayerControllerB me = Me;
				if (!quickMenuClosed && (Object)(object)me != (Object)null && (Object)(object)me.quickMenuManager != (Object)null && !me.quickMenuManager.menuContainer.activeSelf)
				{
					me.quickMenuManager.isMenuOpen = false;
					Cursor.lockState = (CursorLockMode)1;
					Cursor.visible = false;
				}
				if (Tab != null)
				{
					Plugin.LastTab.Value = Tab;
				}
			}
		}

		private void Update()
		{
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOpen)
			{
				return;
			}
			PlayerControllerB me = Me;
			if ((Object)(object)me == (Object)null || (Object)(object)me.quickMenuManager == (Object)null || !me.quickMenuManager.isMenuOpen)
			{
				Close(quickMenuClosed: true);
				return;
			}
			if (me.isPlayerDead || !me.isPlayerControlled || me.inTerminalMenu)
			{
				Close();
				return;
			}
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			Keyboard current = Keyboard.current;
			if (current != null)
			{
				if (((ButtonControl)current.upArrowKey).wasPressedThisFrame)
				{
					Move(-1);
				}
				if (((ButtonControl)current.downArrowKey).wasPressedThisFrame)
				{
					Move(1);
				}
				if (((ButtonControl)current.leftArrowKey).wasPressedThisFrame)
				{
					StepTab(-1);
				}
				if (((ButtonControl)current.rightArrowKey).wasPressedThisFrame)
				{
					StepTab(1);
				}
				if (((ButtonControl)current.enterKey).wasPressedThisFrame || ((ButtonControl)current.numpadEnterKey).wasPressedThisFrame)
				{
					RunRow(Cursor);
				}
				if (((ButtonControl)current.backspaceKey).wasPressedThisFrame && Search.Length > 0)
				{
					SetSearch(Search.Substring(0, Search.Length - 1));
				}
			}
			Mouse current2 = Mouse.current;
			if (current2 != null)
			{
				float y = ((InputControl<Vector2>)(object)current2.scroll).ReadValue().y;
				if (y != 0f)
				{
					Scroll = Mathf.Clamp(Scroll + ((!(y > 0f)) ? 1 : (-1)), 0, Mathf.Max(0, Rows.Count - 8));
					_panel.Redraw();
				}
			}
			if (_builtVersion != MenuApi.Version)
			{
				Rebuild();
			}
			else if (Time.unscaledTime >= _nextRefresh)
			{
				_nextRefresh = Time.unscaledTime + 0.25f;
				RefreshBlocked();
				_panel.Redraw();
			}
		}

		private void OnText(char c)
		{
			if (IsOpen && !char.IsControl(c) && Search.Length < 24)
			{
				SetSearch(Search + c);
			}
		}

		internal List<string> TabList()
		{
			List<string> list = new List<string>();
			HashSet<string> fav = Plugin.Favourites;
			if (Shown().Any((MenuApi.Entry e) => fav.Contains(e.Key)))
			{
				list.Add("Favourites");
			}
			list.AddRange(MenuApi.Tabs.Where((string t) => Shown().Any((MenuApi.Entry e) => e.Tab == t)));
			return list;
		}

		private static IEnumerable<MenuApi.Entry> Shown()
		{
			return MenuApi.Entries.Where((MenuApi.Entry e) => !e.Cheat || Plugin.CheatsEnabled.Value);
		}

		internal void Rebuild()
		{
			_builtVersion = MenuApi.Version;
			Rows.Clear();
			List<string> list = TabList();
			if (Search.Length > 0)
			{
				string s = Search.ToLowerInvariant();
				foreach (string t in MenuApi.Tabs)
				{
					List<MenuApi.Entry> list2 = (from e in Shown()
						where e.Tab == t && (e.Label.ToLowerInvariant().Contains(s) || t.ToLowerInvariant().Contains(s))
						select e).ToList();
					if (list2.Count != 0)
					{
						Rows.Add(new Row
						{
							Heading = t
						});
						Rows.AddRange(list2.Select((MenuApi.Entry e) => new Row
						{
							Entry = e
						}));
					}
				}
			}
			else
			{
				if (Tab == null || !list.Contains(Tab))
				{
					Tab = list.FirstOrDefault();
				}
				HashSet<string> fav = Plugin.Favourites;
				IEnumerable<MenuApi.Entry> source = ((Tab == "Favourites") ? (from e in Shown()
					where fav.Contains(e.Key)
					select e) : (from e in Shown()
					where e.Tab == Tab
					select e));
				Rows.AddRange(source.Select((MenuApi.Entry e) => new Row
				{
					Entry = e
				}));
			}
			RefreshBlocked();
			Cursor = Mathf.Clamp(Cursor, 0, Mathf.Max(0, Rows.Count - 1));
			if (Rows.Count > 0 && Rows[Cursor].Entry == null)
			{
				Cursor = Math.Min(Cursor + 1, Rows.Count - 1);
			}
			KeepCursorVisible();
			_panel?.Redraw();
		}

		internal void RefreshBlocked()
		{
			bool flag = (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost;
			foreach (Row row in Rows)
			{
				if (row.Entry == null)
				{
					continue;
				}
				string blocked = null;
				if (row.Entry.Host && !flag)
				{
					blocked = "host only";
				}
				else if (row.Entry.Unavailable != null)
				{
					try
					{
						blocked = row.Entry.Unavailable();
					}
					catch (Exception ex)
					{
						blocked = "error";
						Plugin.Log.LogWarning((object)("ModMenu: " + row.Entry.Key + " check failed: " + ex.Message));
					}
				}
				row.Blocked = blocked;
			}
		}

		internal void SetSearch(string s)
		{
			Search = s;
			Cursor = 0;
			Scroll = 0;
			Rebuild();
		}

		internal void SelectTab(string t)
		{
			Tab = t;
			Search = "";
			Cursor = 0;
			Scroll = 0;
			Plugin.LastTab.Value = t;
			Rebuild();
		}

		private void StepTab(int d)
		{
			List<string> list = TabList();
			if (list.Count != 0)
			{
				int num = ((Search.Length <= 0) ? Math.Max(0, list.IndexOf(Tab)) : 0);
				SelectTab(list[(num + d + list.Count) % list.Count]);
			}
		}

		private void Move(int d)
		{
			if (Rows.Count == 0)
			{
				return;
			}
			int num = Cursor;
			for (int i = 0; i < Rows.Count; i++)
			{
				num = (num + d + Rows.Count) % Rows.Count;
				if (Rows[num].Entry != null)
				{
					break;
				}
			}
			Cursor = num;
			KeepCursorVisible();
			_panel.Redraw();
		}

		private void KeepCursorVisible()
		{
			if (Cursor < Scroll)
			{
				Scroll = ((Cursor > 0 && Rows[Cursor - 1].Entry == null) ? (Cursor - 1) : Cursor);
			}
			if (Cursor >= Scroll + 8)
			{
				Scroll = Cursor - 8 + 1;
			}
			Scroll = Mathf.Clamp(Scroll, 0, Mathf.Max(0, Rows.Count - 8));
		}

		internal void ToggleFavourite(int row)
		{
			if (row >= 0 && row < Rows.Count && Rows[row].Entry != null)
			{
				MenuApi.Entry entry = Rows[row].Entry;
				Plugin.SetFavourite(entry.Key, !Plugin.Favourites.Contains(entry.Key));
				Rebuild();
			}
		}

		internal string RunRow(int row)
		{
			if (row < 0 || row >= Rows.Count || Rows[row].Entry == null)
			{
				return null;
			}
			Cursor = row;
			RefreshBlocked();
			Row row2 = Rows[row];
			MenuApi.Entry entry = row2.Entry;
			if (row2.Blocked != null)
			{
				Tip(entry.Tab, entry.Label + ": " + row2.Blocked + ".");
				_panel?.Redraw();
				return null;
			}
			string text;
			try
			{
				text = (entry.IsToggle ? entry.Set(!entry.Get()) : entry.Run());
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"ModMenu: {entry.Key} failed: {arg}");
				Tip(entry.Tab, entry.Label + " failed (see the log).");
				return null;
			}
			Plugin.Log.LogInfo((object)("ModMenu: " + entry.Key + " -> " + (text ?? "(nothing)")));
			if (text != null)
			{
				Tip(entry.Tab, Capital(text) + ".");
				if (entry.Cheat && Plugin.Announce.Value)
				{
					AnnounceCheat(text);
				}
			}
			RefreshBlocked();
			_panel?.Redraw();
			return text;
		}

		internal static void AnnounceCheat(string result)
		{
			HUDManager instance = HUDManager.Instance;
			PlayerControllerB me = Me;
			if ((Object)(object)instance == (Object)null || (Object)(object)me == (Object)null)
			{
				return;
			}
			try
			{
				instance.AddTextToChatOnServer("<color=#9a9a9a>" + me.playerUsername + " " + result + " [Mod Menu]</color>", -1);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("ModMenu: chat announce failed: " + ex.Message));
			}
		}

		internal static void Tip(string title, string body)
		{
			try
			{
				HUDManager instance = HUDManager.Instance;
				if (instance != null)
				{
					instance.DisplayTip(title, body, false, false, "LC_Tip1");
				}
			}
			catch
			{
			}
		}

		private static string Capital(string s)
		{
			if (!string.IsNullOrEmpty(s))
			{
				return char.ToUpperInvariant(s[0]) + s.Substring(1);
			}
			return s;
		}
	}
	public static class MenuApi
	{
		internal class Entry
		{
			public string Tab;

			public string Label;

			public string Note;

			public Func<string> Run;

			public Func<bool> Get;

			public Func<bool, string> Set;

			public Func<string> Unavailable;

			public bool Host;

			public bool Cheat;

			public bool IsToggle => Get != null;

			public string Key => Tab + "/" + Label;
		}

		internal static readonly List<Entry> Entries = new List<Entry>();

		internal static readonly List<string> Tabs = new List<string>();

		internal static int Version;

		public static void Button(string tab, string label, Func<string> run, bool host = false, bool cheat = false, Func<string> unavailable = null, string note = null)
		{
			Add(new Entry
			{
				Tab = tab,
				Label = label,
				Run = run,
				Host = host,
				Cheat = cheat,
				Unavailable = unavailable,
				Note = note
			});
		}

		public static void Toggle(string tab, string label, Func<bool> get, Func<bool, string> set, bool host = false, bool cheat = false, Func<string> unavailable = null, string note = null)
		{
			Add(new Entry
			{
				Tab = tab,
				Label = label,
				Get = get,
				Set = set,
				Host = host,
				Cheat = cheat,
				Unavailable = unavailable,
				Note = note
			});
		}

		public static void Choice(string tab, string label, string[] options, Func<int, string> run, bool host = false, bool cheat = false, Func<string> unavailable = null, string note = null)
		{
			for (int i = 0; i < options.Length; i++)
			{
				int k = i;
				Add(new Entry
				{
					Tab = tab,
					Label = label + ": " + options[i],
					Run = () => run(k),
					Host = host,
					Cheat = cheat,
					Unavailable = unavailable,
					Note = note
				});
			}
		}

		public static void ClearTab(string tab)
		{
			Entries.RemoveAll((Entry e) => e.Tab == tab);
			Tabs.RemoveAll((string t) => t == tab);
			Version++;
		}

		private static void Add(Entry e)
		{
			if (string.IsNullOrEmpty(e.Tab) || string.IsNullOrEmpty(e.Label))
			{
				throw new ArgumentException("ModMenu: tab and label are required.");
			}
			Entries.RemoveAll((Entry x) => x.Key == e.Key);
			Entries.Add(e);
			if (!Tabs.Contains(e.Tab))
			{
				Tabs.Add(e.Tab);
			}
			Version++;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogDebug((object)("ModMenu: registered " + e.Key));
			}
		}
	}
	internal class Panel : MonoBehaviour
	{
		private class RowUi
		{
			public GameObject Go;

			public Image Bg;

			public TextMeshProUGUI Star;

			public TextMeshProUGUI Label;

			public TextMeshProUGUI Note;

			public TextMeshProUGUI Act;

			public TextMeshProUGUI Heading;
		}

		private static readonly Color Green = Color32.op_Implicit(new Color32((byte)60, byte.MaxValue, (byte)90, byte.MaxValue));

		private static readonly Color Dim = Color32.op_Implicit(new Color32((byte)40, (byte)150, (byte)60, byte.MaxValue));

		private static readonly Color Orange = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)140, (byte)30, byte.MaxValue));

		private static readonly Color Grey = Color32.op_Implicit(new Color32((byte)115, (byte)125, (byte)115, byte.MaxValue));

		private static readonly Color Back = Color32.op_Implicit(new Color32((byte)6, (byte)14, (byte)8, (byte)240));

		private static readonly Color RowBack = Color32.op_Implicit(new Color32((byte)12, (byte)30, (byte)16, byte.MaxValue));

		private static readonly Color RowSel = Color32.op_Implicit(new Color32((byte)30, (byte)90, (byte)40, byte.MaxValue));

		private static readonly Color Line = Color32.op_Implicit(new Color32((byte)30, (byte)80, (byte)40, byte.MaxValue));

		private const float W = 1200f;

		private const float H = 760f;

		private const float TabW = 260f;

		private const float RowH = 64f;

		private const float Pad = 24f;

		private const int MaxTabs = 12;

		private Menu _menu;

		private TMP_FontAsset _font;

		private TextMeshProUGUI _search;

		private TextMeshProUGUI _footer;

		private TextMeshProUGUI _heading;

		private readonly List<(Image bg, TextMeshProUGUI text)> _tabs = new List<(Image, TextMeshProUGUI)>();

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

		internal static Panel Create(Menu menu)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("ModMenu.Canvas");
			Object.DontDestroyOnLoad((Object)(object)val);
			Canvas obj = val.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 900;
			CanvasScaler obj2 = val.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.matchWidthOrHeight = 0.5f;
			val.AddComponent<GraphicRaycaster>();
			Panel panel = val.AddComponent<Panel>();
			panel._menu = menu;
			panel.Build();
			val.SetActive(false);
			return panel;
		}

		private TMP_FontAsset FindFont()
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			if ((Object)(object)val != (Object)null && (Object)(object)val.screenText != (Object)null && (Object)(object)val.screenText.textComponent != (Object)null)
			{
				return val.screenText.textComponent.font;
			}
			if ((Object)(object)HUDManager.Instance != (Object)null && (Object)(object)HUDManager.Instance.chatText != (Object)null)
			{
				return ((TMP_Text)HUDManager.Instance.chatText).font;
			}
			return TMP_Settings.defaultFontAsset;
		}

		private void Build()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: 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)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: 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_01dc: 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: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f8: 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_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0449: Unknown result type (might be due to invalid IL or missing references)
			//IL_045a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0479: Unknown result type (might be due to invalid IL or missing references)
			//IL_0488: Unknown result type (might be due to invalid IL or missing references)
			//IL_0499: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_053c: Unknown result type (might be due to invalid IL or missing references)
			//IL_054b: Unknown result type (might be due to invalid IL or missing references)
			//IL_055a: Unknown result type (might be due to invalid IL or missing references)
			_font = FindFont();
			EnsureEventSystem();
			RectTransform val = Rect("Box", ((Component)this).transform, new Vector2(1200f, 760f), Vector2.zero);
			Img((Transform)(object)val, Back);
			Outline((Transform)(object)val, Green, 2f);
			Text((Transform)(object)val, "MOD MENU", 34f, Orange, new Vector2(24f, -24f), new Vector2(400f, 44f), (FontStyles)1);
			TextMeshProUGUI obj = Text((Transform)(object)val, "", 20f, Dim, new Vector2(816f, -32f), new Vector2(360f, 30f), (FontStyles)0);
			((TMP_Text)obj).alignment = (TextAlignmentOptions)516;
			((Object)((Component)obj).gameObject).name = "CloseHint";
			RectTransform val2 = Rect("SearchBox", (Transform)(object)val, new Vector2(1152f, 40f), new Vector2(24f, -80f), topLeft: true);
			Outline((Transform)(object)val2, Dim, 1f);
			_search = Text((Transform)(object)val2, "", 22f, Green, new Vector2(12f, -6f), new Vector2(1128f, 30f), (FontStyles)0);
			for (int i = 0; i < 12; i++)
			{
				int k = i;
				RectTransform val3 = Rect("Tab" + i, (Transform)(object)val, new Vector2(250f, 42f), new Vector2(24f, (float)(-140 - i * 46)), topLeft: true);
				Image item = Img((Transform)(object)val3, new Color(0f, 0f, 0f, 0f));
				TextMeshProUGUI item2 = Text((Transform)(object)val3, "", 22f, Dim, new Vector2(12f, -8f), new Vector2(230f, 30f), (FontStyles)0);
				Click((Transform)(object)val3, delegate
				{
					OnTab(k);
				});
				_tabs.Add((item, item2));
			}
			Img((Transform)(object)Rect("Divider", (Transform)(object)val, new Vector2(1f, 560f), new Vector2(288f, -136f), topLeft: true), Dim);
			float num = 312f;
			float num2 = 1200f - num - 24f;
			_heading = Text((Transform)(object)val, "", 24f, Orange, new Vector2(num, -140f), new Vector2(num2, 32f), (FontStyles)1);
			for (int num3 = 0; num3 < 8; num3++)
			{
				int k2 = num3;
				RowUi rowUi = new RowUi();
				RectTransform val4 = Rect("Row" + num3, (Transform)(object)val, new Vector2(num2, 56f), new Vector2(num, -180f - (float)num3 * 64f), topLeft: true);
				rowUi.Go = ((Component)val4).gameObject;
				rowUi.Bg = Img((Transform)(object)val4, RowBack);
				Outline((Transform)(object)val4, Line, 1f);
				rowUi.Heading = Text((Transform)(object)val4, "", 20f, Orange, new Vector2(4f, -18f), new Vector2(num2 - 8f, 28f), (FontStyles)1);
				RectTransform val5 = Rect("Star", (Transform)(object)val4, new Vector2(40f, 56f), new Vector2(0f, 0f), topLeft: true);
				Img((Transform)(object)val5, new Color(0f, 0f, 0f, 0f));
				rowUi.Star = Text((Transform)(object)val5, "", 26f, Dim, new Vector2(10f, -10f), new Vector2(30f, 34f), (FontStyles)0);
				Click((Transform)(object)val5, delegate
				{
					_menu.ToggleFavourite(_menu.Scroll + k2);
				});
				rowUi.Label = Text((Transform)(object)val4, "", 24f, Green, new Vector2(48f, -4f), new Vector2(num2 - 260f, 30f), (FontStyles)0);
				rowUi.Note = Text((Transform)(object)val4, "", 16f, Dim, new Vector2(48f, -32f), new Vector2(num2 - 260f, 22f), (FontStyles)0);
				rowUi.Act = Text((Transform)(object)val4, "", 24f, Green, new Vector2(num2 - 200f, -14f), new Vector2(180f, 30f), (FontStyles)1);
				((TMP_Text)rowUi.Act).alignment = (TextAlignmentOptions)516;
				Click((Transform)(object)val4, delegate
				{
					_menu.RunRow(_menu.Scroll + k2);
				});
				((Transform)val5).SetAsLastSibling();
				_rows.Add(rowUi);
			}
			_footer = Text((Transform)(object)val, "", 18f, Dim, new Vector2(24f, -716f), new Vector2(1152f, 26f), (FontStyles)0);
		}

		private void OnTab(int i)
		{
			List<string> list = _menu.TabList();
			if (i < list.Count)
			{
				_menu.SelectTab(list[i]);
			}
		}

		internal void Redraw()
		{
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0475: Unknown result type (might be due to invalid IL or missing references)
			//IL_046e: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04db: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_font == (Object)null))
			{
				string name = ((Object)_font).name;
				TMP_FontAsset defaultFontAsset = TMP_Settings.defaultFontAsset;
				if (!(name == ((defaultFontAsset != null) ? ((Object)defaultFontAsset).name : null)))
				{
					goto IL_005a;
				}
			}
			TMP_FontAsset val = FindFont();
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)_font)
			{
				SetFont(val);
			}
			goto IL_005a;
			IL_005a:
			List<string> list = _menu.TabList();
			bool flag = _menu.Search.Length > 0;
			for (int i = 0; i < _tabs.Count; i++)
			{
				(Image bg, TextMeshProUGUI text) tuple = _tabs[i];
				Image item = tuple.bg;
				TextMeshProUGUI item2 = tuple.text;
				bool flag2 = i < list.Count;
				((Component)item).gameObject.SetActive(flag2);
				if (flag2)
				{
					bool flag3 = !flag && list[i] == _menu.Tab;
					((TMP_Text)item2).text = list[i];
					((Graphic)item2).color = (flag3 ? Green : Dim);
					((TMP_Text)item2).fontStyle = (FontStyles)(flag3 ? 1 : 0);
					((Graphic)item).color = (Color)(flag3 ? RowSel : new Color(0f, 0f, 0f, 0f));
				}
			}
			((TMP_Text)_search).text = (flag ? ("Search: " + _menu.Search + "_") : "<color=#2a7a3a>Type to search</color>");
			((TMP_Text)_heading).text = (flag ? $"{Count()} MATCHES" : (_menu.Tab ?? "No mods registered").ToUpperInvariant());
			((TMP_Text)((Component)((Component)this).transform.Find("Box/CloseHint")).GetComponent<TextMeshProUGUI>()).text = Keys.Shown + " / Esc to close";
			HashSet<string> favourites = Plugin.Favourites;
			for (int j = 0; j < _rows.Count; j++)
			{
				RowUi rowUi = _rows[j];
				int num = _menu.Scroll + j;
				if (num >= _menu.Rows.Count)
				{
					rowUi.Go.SetActive(false);
					continue;
				}
				rowUi.Go.SetActive(true);
				Menu.Row row = _menu.Rows[num];
				bool flag4 = row.Entry == null;
				((Component)rowUi.Heading).gameObject.SetActive(flag4);
				((Component)((TMP_Text)rowUi.Star).transform.parent).gameObject.SetActive(!flag4);
				((Component)rowUi.Label).gameObject.SetActive(!flag4);
				((Component)rowUi.Note).gameObject.SetActive(!flag4);
				((Component)rowUi.Act).gameObject.SetActive(!flag4);
				((Graphic)rowUi.Bg).color = (Color)(flag4 ? new Color(0f, 0f, 0f, 0f) : ((num == _menu.Cursor) ? RowSel : RowBack));
				if (flag4)
				{
					((TMP_Text)rowUi.Heading).text = row.Heading.ToUpperInvariant();
					continue;
				}
				MenuApi.Entry entry = row.Entry;
				bool flag5 = row.Blocked == null;
				bool flag6 = favourites.Contains(entry.Key);
				((TMP_Text)rowUi.Star).text = (flag6 ? G('★', "*") : G('☆', "+"));
				((Graphic)rowUi.Star).color = (flag6 ? Orange : Dim);
				((TMP_Text)rowUi.Label).text = entry.Label;
				((Graphic)rowUi.Label).color = (flag5 ? Green : Grey);
				List<string> list2 = new List<string>();
				if (row.Blocked != null)
				{
					list2.Add(row.Blocked);
				}
				else
				{
					if (entry.Host)
					{
						list2.Add("host");
					}
					if (entry.Cheat)
					{
						list2.Add("cheat");
					}
				}
				if (entry.Note != null)
				{
					list2.Add(entry.Note);
				}
				((TMP_Text)rowUi.Note).text = string.Join(" · ", list2);
				((Graphic)rowUi.Note).color = (flag5 ? Dim : Grey);
				((TMP_Text)rowUi.Act).text = ((!entry.IsToggle) ? "[ RUN ]" : (SafeGet(entry) ? "[ ON ]" : "[ OFF ]"));
				((Graphic)rowUi.Act).color = ((!flag5) ? Grey : ((entry.IsToggle && SafeGet(entry)) ? Orange : Green));
			}
			string text = ((_menu.Rows.Count > 8) ? $"   rows {_menu.Scroll + 1}-{Mathf.Min(_menu.Rows.Count, _menu.Scroll + 8)} of {_menu.Rows.Count}" : "");
			((TMP_Text)_footer).text = G('↑', "Up") + G('↓', "/Down") + " rows  " + G('←', "Left") + G('→', "/Right") + " tabs  Enter run  " + G('☆', "+") + " favourite   Cheats: " + (Plugin.CheatsEnabled.Value ? "on" : "hidden") + (Plugin.Announce.Value ? ", announced in chat" : "") + text;
		}

		private string G(char c, string plain)
		{
			if (!((Object)(object)_font != (Object)null) || !_font.HasCharacter(c, true, false))
			{
				return plain;
			}
			return c.ToString();
		}

		private int Count()
		{
			int num = 0;
			foreach (Menu.Row row in _menu.Rows)
			{
				if (row.Entry != null)
				{
					num++;
				}
			}
			return num;
		}

		private static bool SafeGet(MenuApi.Entry e)
		{
			try
			{
				return e.Get();
			}
			catch
			{
				return false;
			}
		}

		private void SetFont(TMP_FontAsset f)
		{
			_font = f;
			TextMeshProUGUI[] componentsInChildren = ((Component)this).GetComponentsInChildren<TextMeshProUGUI>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((TMP_Text)componentsInChildren[i]).font = f;
			}
		}

		private static void EnsureEventSystem()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)EventSystem.current != (Object)null))
			{
				GameObject val = new GameObject("ModMenu.EventSystem");
				Object.DontDestroyOnLoad((Object)val);
				val.AddComponent<EventSystem>();
				val.AddComponent<InputSystemUIInputModule>();
			}
		}

		private static RectTransform Rect(string name, Transform parent, Vector2 size, Vector2 pos, bool topLeft = false)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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)
			RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }).transform;
			((Transform)val).SetParent(parent, false);
			if (topLeft)
			{
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(0f, 1f);
				val.anchorMax = val2;
				val.anchorMin = val2;
				val.pivot = new Vector2(0f, 1f);
			}
			val.sizeDelta = size;
			val.anchoredPosition = pos;
			return val;
		}

		private static Image Img(Transform t, Color c)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Image obj = ((Component)t).gameObject.AddComponent<Image>();
			((Graphic)obj).color = c;
			return obj;
		}

		private static void Outline(Transform t, Color c, float w)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Outline obj = ((Component)t).gameObject.AddComponent<Outline>();
			((Shadow)obj).effectColor = c;
			((Shadow)obj).effectDistance = new Vector2(w, 0f - w);
			((Shadow)obj).useGraphicAlpha = false;
		}

		private TextMeshProUGUI Text(Transform parent, string s, float size, Color c, Vector2 pos, Vector2 box, FontStyles style = (FontStyles)0)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI val = ((Component)Rect("Text", parent, box, pos, topLeft: true)).gameObject.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)_font != (Object)null)
			{
				((TMP_Text)val).font = _font;
			}
			((TMP_Text)val).text = s;
			((TMP_Text)val).fontSize = size;
			((Graphic)val).color = c;
			((TMP_Text)val).fontStyle = style;
			((TMP_Text)val).enableWordWrapping = false;
			((TMP_Text)val).overflowMode = (TextOverflowModes)1;
			((Graphic)val).raycastTarget = false;
			((TMP_Text)val).richText = true;
			return val;
		}

		private static void Click(Transform t, Action a)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			((Graphic)(((object)((Component)t).GetComponent<Graphic>()) ?? ((object)Img(t, new Color(0f, 0f, 0f, 0f))))).raycastTarget = true;
			Button obj = ((Component)t).gameObject.AddComponent<Button>();
			((Selectable)obj).transition = (Transition)0;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)obj).navigation = navigation;
			((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
			{
				a();
			});
		}
	}
	public static class PluginInfo
	{
		public const string Guid = "daniel.lethalcompany.modmenu";

		public const string Name = "ModMenu";

		public const string Version = "0.1.0";
	}
	[BepInPlugin("daniel.lethalcompany.modmenu", "ModMenu", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> CheatsEnabled;

		internal static ConfigEntry<bool> Announce;

		internal static ConfigEntry<string> OpenKey;

		internal static ConfigEntry<string> FavouritesCfg;

		internal static ConfigEntry<string> LastTab;

		internal static bool InputUtilsLoaded;

		private readonly Harmony _harmony = new Harmony("daniel.lethalcompany.modmenu");

		internal static HashSet<string> Favourites => new HashSet<string>(from s in (FavouritesCfg.Value ?? "").Split(';')
			where s.Length > 0
			select s);

		private void Awake()
		{
			//IL_00d5: 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_00e0: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			CheatsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Cheats", "Enabled", true, "Show cheat rows (spawning, Pirate Shop on/off). Cheats only ever run for the host. Off hides them, for a serious run.");
			Announce = ((BaseUnityPlugin)this).Config.Bind<bool>("Cheats", "Announce", true, "When the host uses a cheat, one grey chat line tells the crew (\"Daniel spawned a safe\").");
			OpenKey = ((BaseUnityPlugin)this).Config.Bind<string>("Keys", "Open key", "<Keyboard>/f6", "Opens and closes the menu. Used when LethalCompany InputUtils isn't installed (with it, rebind in Settings > Controls).");
			FavouritesCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Saved", "Favourites", "", "Starred rows (tab/label;...). Set from the menu.");
			LastTab = ((BaseUnityPlugin)this).Config.Bind<string>("Saved", "Last tab", "", "The tab the menu opens on. Set from the menu.");
			InputUtilsLoaded = Chainloader.PluginInfos.ContainsKey("com.rune580.LethalCompanyInputUtils");
			Keys.Init();
			GameObject val = new GameObject("ModMenu.Menu");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<Menu>();
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)("ModMenu 0.1.0 loaded (InputUtils " + (InputUtilsLoaded ? "found" : "not found") + ")."));
		}

		internal static void SetFavourite(string key, bool on)
		{
			HashSet<string> favourites = Favourites;
			if (on)
			{
				favourites.Add(key);
			}
			else
			{
				favourites.Remove(key);
			}
			FavouritesCfg.Value = string.Join(";", favourites);
		}
	}
	internal static class Keys
	{
		private static InputAction _open;

		internal static string Shown
		{
			get
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					return (_open != null && _open.bindings.Count > 0) ? InputActionRebindingExtensions.GetBindingDisplayString(_open, 0, (DisplayStringOptions)0) : "F6";
				}
				catch
				{
					return "F6";
				}
			}
		}

		internal static void Init()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (Plugin.InputUtilsLoaded)
			{
				_open = FromInputUtils();
			}
			if (_open == null)
			{
				_open = InputActionSetupExtensions.AddAction(new InputActionMap("ModMenu"), "ModMenu.Open", (InputActionType)1, Plugin.OpenKey.Value, (string)null, (string)null, (string)null, (string)null);
				_open.Enable();
			}
			_open.performed += delegate
			{
				Menu.Instance?.Toggle();
			};
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static InputAction FromInputUtils()
		{
			return MenuInputs.Instance.Open;
		}
	}
	internal class MenuInputs : LcInputActions
	{
		internal static readonly MenuInputs Instance = new MenuInputs();

		[InputAction("<Keyboard>/f6", Name = "Open mod menu")]
		public InputAction Open { get; set; }
	}
	[HarmonyPatch]
	internal static class Patches
	{
		[HarmonyPatch(typeof(HUDManager), "EnableChat_performed")]
		[HarmonyPrefix]
		private static bool NoChatWhileOpen()
		{
			if (!((Object)(object)Menu.Instance == (Object)null))
			{
				return !Menu.Instance.IsOpen;
			}
			return true;
		}
	}
}