Decompiled source of Hotkey Helper v1.1.0

BepInEx/plugins/HotkeyHelper.dll

Decompiled a month 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 System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("HotkeyHelper")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+0e0c852d48d4bf4db1b9e86dd7abcbea0ae85713")]
[assembly: AssemblyProduct("HotkeyHelper")]
[assembly: AssemblyTitle("HotkeyHelper")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace HotkeyHelper;

[BepInPlugin("com.mous.hotkeyhelper", "Hotkey Helper", "1.1.0")]
public class HotkeyHelperPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.mous.hotkeyhelper";

	public const string PluginName = "Hotkey Helper";

	public const string PluginVersion = "1.1.0";

	internal static HotkeyHelperPlugin Instance;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<bool> ShowColumn;

	internal static ConfigEntry<bool> ShowInventoryColumn;

	internal static ConfigEntry<int> MaxRows;

	internal static ConfigEntry<Vector2> ColumnPosition;

	internal static ConfigEntry<Vector2> InventoryColumnPosition;

	internal const int ColumnSortingOrder = 1000;

	internal static ConfigEntry<float> ColumnFontSize;

	internal static ConfigEntry<float> OverlayFontSize;

	internal static ConfigEntry<int> OverlayColumns;

	internal static ConfigEntry<Vector2> OverlaySize;

	internal static ConfigEntry<KeyboardShortcut> ShowAllKey;

	internal static ConfigEntry<bool> DebugDump;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Expected O, but got Unknown
		//IL_00b3: 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_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Expected O, but got Unknown
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Expected O, but got Unknown
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Expected O, but got Unknown
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_0228: Unknown result type (might be due to invalid IL or missing references)
		//IL_0232: Expected O, but got Unknown
		Instance = this;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Master switch: the side column and the show-all list.");
		ShowColumn = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "ShowColumn", true, "Show the side column while building, fighting, fishing or in the radial menu.");
		ShowInventoryColumn = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "ShowInventoryColumn", true, "Show the side column while the inventory, a chest or a crafting station is open.");
		MaxRows = ((BaseUnityPlugin)this).Config.Bind<int>("1 - General", "MaxRows", 15, new ConfigDescription("Max hotkeys listed in the side column.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 40), Array.Empty<object>()));
		ColumnPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("2 - Layout", "ColumnPosition", new Vector2(0.995f, 0.4f), "Screen position of the column's right-middle point (0..1, x from left, y from bottom) while building/fighting.");
		InventoryColumnPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("2 - Layout", "InventoryColumnPosition", new Vector2(0.995f, 0.09f), "Screen position of the column's bottom-right corner (column grows upward) while inventory, chest or crafting is open.");
		ColumnFontSize = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Layout", "ColumnFontSize", 14f, new ConfigDescription("Font size of the side column.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 32f), Array.Empty<object>()));
		OverlayFontSize = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Layout", "OverlayFontSize", 20f, new ConfigDescription("Font size of the show-all list (shrinks only if the list doesn't fit).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 36f), Array.Empty<object>()));
		OverlayColumns = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Layout", "OverlayColumns", 2, new ConfigDescription("Number of columns in the show-all list; more columns fit more rows at a larger font.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>()));
		OverlaySize = ((BaseUnityPlugin)this).Config.Bind<Vector2>("2 - Layout", "OverlaySize", new Vector2(0.76f, 0.84f), "Width and height of the show-all list as screen fractions (0..1, centered). Taller fits more rows.");
		ShowAllKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1 - General", "ShowAllKey", new KeyboardShortcut((KeyCode)104, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Hold to show every discovered mod hotkey.");
		DebugDump = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - Debug", "DumpOnWorldLoad", false, "Log the KeyHints UI hierarchy and all discovered hotkeys with their resolved contexts.");
		_harmony = new Harmony("com.mous.hotkeyhelper");
		_harmony.PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Hotkey Helper 1.1.0 loaded");
	}

	private void Update()
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)Hud.instance == (Object)null))
		{
			int visible;
			if (Enabled.Value)
			{
				KeyboardShortcut value = ShowAllKey.Value;
				visible = (((KeyboardShortcut)(ref value)).IsPressed() ? 1 : 0);
			}
			else
			{
				visible = 0;
			}
			AllHotkeysOverlay.SetVisible((byte)visible != 0);
		}
	}

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

	internal static void Log(string msg)
	{
		((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg);
	}

	internal static void Warn(string msg)
	{
		((BaseUnityPlugin)Instance).Logger.LogWarning((object)msg);
	}
}
internal sealed class Hotkey
{
	public string Guid;

	public string PluginName;

	public string Section;

	public string Key;

	public string Description;

	public string AutoContexts;

	public ConfigEntryBase Entry;

	public ConfigEntry<string> Override;

	public HashSet<string> Contexts = new HashSet<string>();

	public string Label;

	public string KeyText => HotkeyScanner.FormatBinding(Entry.BoxedValue);

	public bool IsGamepad => ((object)HotkeyScanner.MainKey(Entry.BoxedValue)/*cast due to .constrained prefix*/).ToString().StartsWith("Joystick");

	public bool IsBound => (int)HotkeyScanner.MainKey(Entry.BoxedValue) > 0;
}
internal static class HotkeyScanner
{
	public static readonly string[] AllContexts = new string[8] { "build", "buildmenu", "combat", "inventory", "container", "fishing", "radial", "general" };

	public static readonly List<Hotkey> Hotkeys = new List<Hotkey>();

	public static bool Dirty = true;

	private static readonly HashSet<ConfigFile> Subscribed = new HashSet<ConfigFile>();

	private static readonly (string guid, Regex key, string contexts)[] KnownMods = new(string, Regex, string)[6]
	{
		("shudnal.ExtraSlots", new Regex("^(Quickslot|Ammo|Food)", RegexOptions.IgnoreCase), "hidden"),
		("Snapheim.Valheim", new Regex(".*"), "build"),
		("Azumatt.AzuAutoStore", new Regex(".*"), "inventory,container"),
		("com.morda.storeandcraft", new Regex(".*"), "inventory,container"),
		("com.nopetrides.valheim.crop-utils", new Regex(".*"), "build"),
		("MK_BetterUI", new Regex(".*"), "general")
	};

	private static readonly (string context, Regex words)[] Keywords = new(string, Regex)[5]
	{
		("fishing", Words("fish")),
		("build", Words("build", "piece", "snap", "place", "rotat", "grid", "hammer", "terrain", "plant", "crop", "hoe", "cultivat")),
		("container", Words("container", "chest", "store", "dump", "take")),
		("inventory", Words("inventory", "craft", "recipe", "favo", "sort", "stack", "equip")),
		("combat", Words("attack", "weapon", "block", "dodge", "shield", "ammo", "bow"))
	};

	private static Regex Words(params string[] w)
	{
		return new Regex("\\b(" + string.Join("|", w) + ")", RegexOptions.IgnoreCase);
	}

	public static void Scan()
	{
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		Hotkeys.Clear();
		ConfigFile config = ((BaseUnityPlugin)HotkeyHelperPlugin.Instance).Config;
		foreach (PluginInfo value2 in Chainloader.PluginInfos.Values)
		{
			if ((Object)(object)value2.Instance == (Object)null || value2.Metadata.GUID == "com.mous.hotkeyhelper")
			{
				continue;
			}
			ConfigFile config2 = value2.Instance.Config;
			if (Subscribed.Add(config2))
			{
				config2.SettingChanged += delegate
				{
					Dirty = true;
				};
			}
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in ((IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)config2).ToList())
			{
				ConfigEntryBase value = item.Value;
				if (!(value.SettingType != typeof(KeyboardShortcut)) || !(value.SettingType != typeof(KeyCode)))
				{
					Hotkey obj = new Hotkey
					{
						Guid = value2.Metadata.GUID,
						PluginName = value2.Metadata.Name,
						Section = item.Key.Section,
						Key = item.Key.Key
					};
					ConfigDescription description = value.Description;
					obj.Description = ((description != null) ? description.Description : null) ?? "";
					obj.Entry = value;
					Hotkey hotkey = obj;
					hotkey.AutoContexts = AutoResolve(hotkey);
					hotkey.Override = config.Bind<string>(Sanitize("Hotkeys - " + hotkey.PluginName), Sanitize(hotkey.Section + " - " + hotkey.Key), "auto", "Where to show '" + hotkey.Key + "'. auto = " + hotkey.AutoContexts + ". Use auto, hidden, or a comma list of: " + string.Join(", ", AllContexts) + ". Optional custom label after ';' (e.g. build;Cycle snap).");
					Resolve(hotkey);
					Hotkeys.Add(hotkey);
				}
			}
		}
		if (Subscribed.Add(config))
		{
			config.SettingChanged += delegate
			{
				Dirty = true;
			};
		}
		Dirty = true;
		string showAll = FormatBinding(HotkeyHelperPlugin.ShowAllKey.Value);
		foreach (Hotkey item2 in Hotkeys.Where((Hotkey h) => h.IsBound && h.KeyText == showAll))
		{
			HotkeyHelperPlugin.Warn("ShowAllKey (" + showAll + ") is also bound by " + item2.PluginName + ": " + item2.Key);
		}
	}

	public static IEnumerable<Hotkey> Visible(bool gamepad)
	{
		return Hotkeys.Where((Hotkey h) => h.IsBound && h.IsGamepad == gamepad && !h.Contexts.Contains("hidden"));
	}

	public static void ResolveAll()
	{
		foreach (Hotkey hotkey in Hotkeys)
		{
			Resolve(hotkey);
		}
	}

	private static void Resolve(Hotkey hk)
	{
		string[] array = (hk.Override.Value ?? "auto").Split(new char[1] { ';' }, 2);
		string text = array[0].Trim();
		if (text == "" || text.Equals("auto", StringComparison.OrdinalIgnoreCase))
		{
			text = hk.AutoContexts;
		}
		hk.Contexts = new HashSet<string>(from c in text.ToLowerInvariant().Split(new char[1] { ',' })
			select c.Trim() into c
			where c != ""
			select c);
		hk.Label = ((array.Length > 1 && array[1].Trim() != "") ? array[1].Trim() : Humanize(hk.Key, hk.PluginName));
	}

	internal static string AutoResolve(Hotkey hk)
	{
		(string, Regex, string)[] knownMods = KnownMods;
		for (int i = 0; i < knownMods.Length; i++)
		{
			var (text, regex, result) = knownMods[i];
			if (text == hk.Guid && regex.IsMatch(hk.Key))
			{
				return result;
			}
		}
		string[] array = new string[2]
		{
			hk.Section + " " + hk.Key + " " + hk.PluginName,
			hk.Description
		};
		foreach (string text2 in array)
		{
			List<string> list = (from k in Keywords
				where k.words.IsMatch(text2)
				select k.context).ToList();
			if (list.Count > 0)
			{
				return string.Join(",", list);
			}
		}
		return "general";
	}

	internal static string Humanize(string key, string fallback)
	{
		string input = Regex.Replace(key, "(?<=[a-z])(?=[A-Z])", " ");
		input = Regex.Replace(input, "(\\s*(hot\\s*key|short\\s*cut|key\\s*bind\\d*|key|gamepad))+\\s*$", "", RegexOptions.IgnoreCase).Trim();
		if (input == "")
		{
			return fallback;
		}
		return char.ToUpperInvariant(input[0]) + input.Substring(1);
	}

	private static string Sanitize(string s)
	{
		return Regex.Replace(s, "[=\\n\\t\\\\\"'\\[\\]]", " ");
	}

	internal static KeyCode MainKey(object binding)
	{
		//IL_0009: 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_0031: 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)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: 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_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		if (!(binding is KeyboardShortcut val))
		{
			if (binding is KeyCode result)
			{
				return result;
			}
			return (KeyCode)0;
		}
		return ((KeyboardShortcut)(ref val)).MainKey;
	}

	internal static string FormatBinding(object binding)
	{
		//IL_0009: 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_0036: 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_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		if (binding is KeyboardShortcut val)
		{
			return string.Join(" + ", ((KeyboardShortcut)(ref val)).Modifiers.Select(KeyName).Concat(new string[1] { KeyName(((KeyboardShortcut)(ref val)).MainKey) }));
		}
		if (!(binding is KeyCode k))
		{
			return "";
		}
		return KeyName(k);
	}

	internal unsafe static string KeyName(KeyCode k)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Invalid comparison between Unknown and I4
		//IL_0005: 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_0032: Expected I4, but got Unknown
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Expected I4, but got Unknown
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Invalid comparison between Unknown and I4
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Expected I4, but got Unknown
		if ((int)k <= 59)
		{
			switch (k - 39)
			{
			default:
				if ((int)k != 59)
				{
					break;
				}
				return ";";
			case 7:
				return ".";
			case 5:
				return ",";
			case 6:
				return "-";
			case 4:
				return "+";
			case 8:
				return "/";
			case 0:
				return "'";
			case 1:
			case 2:
			case 3:
				break;
			}
		}
		else
		{
			if ((int)k == 61)
			{
				return "=";
			}
			switch (k - 91)
			{
			default:
				switch (k - 323)
				{
				case 0:
					return "LMB";
				case 1:
					return "RMB";
				case 2:
					return "MMB";
				}
				break;
			case 0:
				return "[";
			case 2:
				return "]";
			case 1:
				return "\\";
			case 5:
				return "`";
			case 3:
			case 4:
				break;
			}
		}
		string text = ((object)(*(KeyCode*)(&k))/*cast due to .constrained prefix*/).ToString();
		if (text.StartsWith("Alpha"))
		{
			return text.Substring(5);
		}
		if (text.StartsWith("Keypad"))
		{
			return "Num" + text.Substring(6);
		}
		if (text.StartsWith("Joystick"))
		{
			return "Pad " + text.Substring(text.IndexOf("Button") + 6);
		}
		return text.Replace("Left", "L").Replace("Right", "R").Replace("Control", "Ctrl");
	}
}
[HarmonyPatch(typeof(KeyHints))]
internal static class ContextColumn
{
	private static GameObject _root;

	private static TextMeshProUGUI _text;

	private static string _lastKey;

	[HarmonyPostfix]
	[HarmonyPatch("Start")]
	private static void Start()
	{
		ConfigFile config = ((BaseUnityPlugin)HotkeyHelperPlugin.Instance).Config;
		config.SaveOnConfigSet = false;
		HotkeyScanner.Scan();
		config.Save();
		config.SaveOnConfigSet = true;
		_lastKey = null;
		if (HotkeyHelperPlugin.DebugDump.Value)
		{
			HotkeyHelperPlugin.Log("Discovered hotkeys:\n" + string.Join("\n", HotkeyScanner.Hotkeys.Select((Hotkey hk) => "  " + hk.PluginName + " | [" + hk.Section + "] " + hk.Key + " = " + hk.KeyText + " | auto=" + hk.AutoContexts + " | shown=" + string.Join(",", hk.Contexts) + " | label=" + hk.Label)));
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch("UpdateHints")]
	private static void UpdateHints(KeyHints __instance)
	{
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: 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_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: 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_0177: Unknown result type (might be due to invalid IL or missing references)
		string[] contexts = ActiveContexts(__instance);
		bool gamepad = ZInput.IsGamepadActive();
		bool flag = contexts != null && contexts.Contains("inventory");
		bool flag2 = (flag ? HotkeyHelperPlugin.ShowInventoryColumn.Value : HotkeyHelperPlugin.ShowColumn.Value);
		string text = ((contexts == null || !HotkeyHelperPlugin.Enabled.Value || !flag2 || AllHotkeysOverlay.Visible) ? null : (string.Join(",", contexts) + gamepad));
		if (text == _lastKey && !HotkeyScanner.Dirty)
		{
			return;
		}
		_lastKey = text;
		HotkeyScanner.Dirty = false;
		HotkeyScanner.ResolveAll();
		List<Hotkey> list = ((text == null) ? new List<Hotkey>() : (from h in HotkeyScanner.Visible(gamepad)
			where contexts.Any(h.Contexts.Contains)
			select h).Take(HotkeyHelperPlugin.MaxRows.Value).ToList());
		if (list.Count == 0)
		{
			if (Object.op_Implicit((Object)(object)_root))
			{
				_root.SetActive(false);
			}
		}
		else if (Object.op_Implicit((Object)(object)_root) || Create())
		{
			RectTransform val = (RectTransform)_root.transform;
			val.pivot = (flag ? new Vector2(1f, 0f) : new Vector2(1f, 0.5f));
			Vector2 anchorMin = (val.anchorMax = (flag ? HotkeyHelperPlugin.InventoryColumnPosition : HotkeyHelperPlugin.ColumnPosition).Value);
			val.anchorMin = anchorMin;
			((TMP_Text)_text).fontSize = HotkeyHelperPlugin.ColumnFontSize.Value;
			((TMP_Text)_text).text = string.Join("\n", list.Select((Hotkey h) => h.Label + "  <color=#ffd27f>" + h.KeyText + "</color>"));
			_root.SetActive(true);
		}
	}

	private static string[] ActiveContexts(KeyHints kh)
	{
		if (kh.m_buildHints.activeSelf)
		{
			if (Hud.IsPieceSelectionVisible())
			{
				return new string[2] { "build", "buildmenu" };
			}
			return new string[1] { "build" };
		}
		if (kh.m_combatHints.activeSelf)
		{
			return new string[1] { "combat" };
		}
		if (kh.m_inventoryWithContainerHints.activeSelf)
		{
			return new string[2] { "inventory", "container" };
		}
		if (kh.m_inventoryHints.activeSelf)
		{
			return new string[1] { "inventory" };
		}
		if (kh.m_fishingHints.activeSelf)
		{
			return new string[1] { "fishing" };
		}
		if (kh.m_radialHints.activeSelf)
		{
			return new string[1] { "radial" };
		}
		return null;
	}

	private static bool Create()
	{
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Expected O, but got Unknown
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Expected O, but got Unknown
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Expected O, but got Unknown
		if (!Ui.TryGetFont(out var font))
		{
			return false;
		}
		_root = new GameObject("HotkeyHelperColumn", new Type[4]
		{
			typeof(RectTransform),
			typeof(Image),
			typeof(VerticalLayoutGroup),
			typeof(ContentSizeFitter)
		});
		RectTransform val = (RectTransform)_root.transform;
		((Transform)val).SetParent(Hud.instance.m_rootObject.transform, false);
		Canvas obj = _root.AddComponent<Canvas>();
		obj.overrideSorting = true;
		obj.sortingOrder = 1000;
		((Graphic)_root.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.45f);
		VerticalLayoutGroup component = _root.GetComponent<VerticalLayoutGroup>();
		((LayoutGroup)component).padding = new RectOffset(10, 10, 6, 6);
		bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)component).childControlHeight = true);
		((HorizontalOrVerticalLayoutGroup)component).childControlWidth = childControlWidth;
		ContentSizeFitter component2 = _root.GetComponent<ContentSizeFitter>();
		FitMode horizontalFit = (FitMode)2;
		component2.verticalFit = (FitMode)2;
		component2.horizontalFit = horizontalFit;
		_text = Ui.Text((Transform)val, font);
		((TMP_Text)_text).alignment = (TextAlignmentOptions)516;
		return true;
	}
}
internal static class AllHotkeysOverlay
{
	private static GameObject _root;

	private static readonly List<TextMeshProUGUI> _columns = new List<TextMeshProUGUI>();

	public static bool Visible
	{
		get
		{
			if (Object.op_Implicit((Object)(object)_root))
			{
				return _root.activeSelf;
			}
			return false;
		}
	}

	public static void SetVisible(bool visible)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: 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_0092: Expected O, but got Unknown
		//IL_00a1: 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)
		if (!visible)
		{
			if (Object.op_Implicit((Object)(object)_root))
			{
				_root.SetActive(false);
			}
		}
		else
		{
			if (Visible || (!Object.op_Implicit((Object)(object)_root) && !Create()))
			{
				return;
			}
			HotkeyScanner.ResolveAll();
			Vector2 value = HotkeyHelperPlugin.OverlaySize.Value;
			float num = Mathf.Clamp(value.x, 0.2f, 1f) / 2f;
			float num2 = Mathf.Clamp(value.y, 0.2f, 1f) / 2f;
			RectTransform val = (RectTransform)_root.transform;
			val.anchorMin = new Vector2(0.5f - num, 0.5f - num2);
			val.anchorMax = new Vector2(0.5f + num, 0.5f + num2);
			int value2 = HotkeyHelperPlugin.OverlayColumns.Value;
			while (_columns.Count < value2)
			{
				_columns.Add(Column(val, ((TMP_Text)_columns[0]).font));
			}
			for (int i = 0; i < _columns.Count; i++)
			{
				((Component)_columns[i]).gameObject.SetActive(i < value2);
				Place(((TMP_Text)_columns[i]).rectTransform, (float)i / (float)value2, (float)(i + 1) / (float)value2, 70f, 24f, fromTop: false);
			}
			List<Hotkey> list = HotkeyScanner.Visible(ZInput.IsGamepadActive()).ToList();
			float keyWidthEm = ((list.Count == 0) ? 4f : ((float)list.Max((Hotkey h) => h.KeyText.Length) * 0.6f + 1f));
			List<List<string>> list2 = (from h in list
				group h by h.PluginName into g
				select new string[1] { "<color=#ffc34d><b>" + g.Key + "</b></color>" }.Concat(g.Select((Hotkey h) => string.Format("<color=#ffffff>{0}</color><pos={1:0.#}em>{2}  <size=75%><color=#8a8a8a>{3}</color></size>", h.KeyText, keyWidthEm, h.Label, string.Join(", ", h.Contexts)))).Concat(new string[1] { "" }).ToList()).ToList();
			List<string>[] array = new List<string>[value2];
			for (int num3 = 0; num3 < value2; num3++)
			{
				array[num3] = new List<string>();
			}
			int[] array2 = SplitColumns(list2.Select((List<string> g) => g.Count).ToArray(), value2);
			for (int num4 = 0; num4 < list2.Count; num4++)
			{
				array[array2[num4]].AddRange(list2[num4]);
			}
			if (list.Count == 0)
			{
				array[0].Add("No mod hotkeys found.");
			}
			for (int num5 = 0; num5 < value2; num5++)
			{
				((TMP_Text)_columns[num5]).text = string.Join("\n", array[num5]);
			}
			_root.SetActive(true);
			List<TextMeshProUGUI> list3 = _columns.Take(value2).ToList();
			foreach (TextMeshProUGUI item in list3)
			{
				((TMP_Text)item).enableAutoSizing = true;
				((TMP_Text)item).fontSizeMax = HotkeyHelperPlugin.OverlayFontSize.Value;
				((TMP_Text)item).ForceMeshUpdate(false, false);
			}
			float fontSize = (from t in list3
				where ((TMP_Text)t).text != ""
				select ((TMP_Text)t).fontSize).DefaultIfEmpty(HotkeyHelperPlugin.OverlayFontSize.Value).Min();
			foreach (TextMeshProUGUI item2 in list3)
			{
				((TMP_Text)item2).enableAutoSizing = false;
				((TMP_Text)item2).fontSize = fontSize;
			}
		}
	}

	internal static int[] SplitColumns(int[] groupLines, int columns)
	{
		int[] array = new int[groupLines.Length];
		float num = (float)groupLines.Sum() / (float)columns;
		int num2 = 0;
		int num3 = 0;
		for (int i = 0; i < groupLines.Length; i++)
		{
			if (num2 < columns - 1 && num3 > 0 && (float)num3 + (float)groupLines[i] / 2f > num * (float)(num2 + 1))
			{
				num2++;
			}
			array[i] = num2;
			num3 += groupLines[i];
		}
		return array;
	}

	private static bool Create()
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Expected O, but got Unknown
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Expected O, but got Unknown
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
		if (!Ui.TryGetFont(out var font))
		{
			return false;
		}
		_root = new GameObject("HotkeyHelperOverlay", new Type[2]
		{
			typeof(RectTransform),
			typeof(Image)
		});
		RectTransform val = (RectTransform)_root.transform;
		((Transform)val).SetParent(Hud.instance.m_rootObject.transform, false);
		Vector2 offsetMin = (val.offsetMax = Vector2.zero);
		val.offsetMin = offsetMin;
		((Graphic)_root.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.85f);
		TextMeshProUGUI obj = Ui.Text((Transform)(object)val, font);
		((TMP_Text)obj).text = "<b>Mod hotkeys</b>";
		((TMP_Text)obj).fontSize = 28f;
		((Graphic)obj).color = new Color(1f, 0.82f, 0.45f);
		Place(((TMP_Text)obj).rectTransform, 0f, 1f, 16f, -60f, fromTop: true);
		_columns.Clear();
		_columns.Add(Column(val, font));
		_root.SetActive(false);
		return true;
	}

	private static TextMeshProUGUI Column(RectTransform parent, TMP_FontAsset font)
	{
		TextMeshProUGUI obj = Ui.Text((Transform)(object)parent, font);
		((TMP_Text)obj).fontSizeMin = 10f;
		((TMP_Text)obj).overflowMode = (TextOverflowModes)3;
		return obj;
	}

	private static void Place(RectTransform rt, float xMin, float xMax, float top, float bottom, bool fromTop)
	{
		//IL_0012: 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_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		rt.anchorMin = new Vector2(xMin, fromTop ? 1f : 0f);
		rt.anchorMax = new Vector2(xMax, 1f);
		rt.offsetMin = new Vector2(32f, bottom);
		rt.offsetMax = new Vector2(-32f, 0f - top);
	}
}
internal static class Ui
{
	public static bool TryGetFont(out TMP_FontAsset font)
	{
		font = ((Object.op_Implicit((Object)(object)KeyHints.instance) && Object.op_Implicit((Object)(object)KeyHints.instance.m_buildMenuKey)) ? ((TMP_Text)KeyHints.instance.m_buildMenuKey).font : null);
		if ((Object)(object)Hud.instance != (Object)null)
		{
			return (Object)(object)font != (Object)null;
		}
		return false;
	}

	public static TextMeshProUGUI Text(Transform parent, TMP_FontAsset font)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: 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)
		GameObject val = new GameObject("Text", new Type[2]
		{
			typeof(RectTransform),
			typeof(TextMeshProUGUI)
		});
		val.transform.SetParent(parent, false);
		TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
		((TMP_Text)component).font = font;
		((TMP_Text)component).richText = true;
		((Graphic)component).color = new Color(0.9f, 0.9f, 0.9f);
		((TMP_Text)component).textWrappingMode = (TextWrappingModes)0;
		return component;
	}
}