Decompiled source of Hotline v1.0.0

Hotline.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using HarmonyLib;
using Hotline;
using Hotline.Bridge;
using Hotline.Config;
using Hotline.Hotkeys;
using Hotline.Logging;
using Hotline.Panels;
using Hotline.UI;
using Il2CppScheduleOne;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "Hotline", "1.0.0", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-Hotline")]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: MelonOptionalDependencies(new string[] { "ModManager&PhoneApp" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Hotline")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+fdf6b5934424a816a61101d2e2f3cce9caa6a542")]
[assembly: AssemblyProduct("Hotline")]
[assembly: AssemblyTitle("Hotline")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 Hotline
{
	public sealed class Core : MelonMod
	{
		private bool _inWorld;

		public static Core Instance { get; private set; }

		public static Instance Log { get; private set; }

		internal static Harmony HarmonyInst { get; private set; }

		public override void OnInitializeMelon()
		{
			//IL_005f: 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)
			Instance = this;
			Log = ((MelonBase)this).LoggerInstance;
			HarmonyInst = ((MelonBase)this).HarmonyInstance;
			Preferences.Initialize();
			LogHub.Install();
			BridgeHost.Install();
			try
			{
				((MelonBase)this).HarmonyInstance.PatchAll();
			}
			catch (Exception ex)
			{
				Log.Warning("[Hotline] Harmony patch failed: " + ex.Message);
			}
			Log.Msg("Hotline v1.0.0 - mod HUD & hotkey hub. Press " + ((object)Preferences.MasterKey/*cast due to .constrained prefix*/).ToString() + " in-world to open the overlay ('hotline help' for commands).");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			_inWorld = sceneName == "Main";
			if (_inWorld)
			{
				Interceptor.Install(((MelonBase)this).HarmonyInstance);
			}
		}

		public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
		{
			_inWorld = false;
		}

		public override void OnUpdate()
		{
			//IL_0011: 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)
			if (!_inWorld || !Preferences.Enabled)
			{
				return;
			}
			try
			{
				if (Input.GetKeyDown(Preferences.MasterKey))
				{
					if (!Preferences.ShowHud || !WindowLayout.IsVisible("overview"))
					{
						Preferences.SetShowHud(v: true);
						WindowLayout.SetVisible("overview", v: true);
						foreach (string item in Interceptor.ModsForKey(Preferences.MasterKey))
						{
							WindowLayout.SetVisible(item, v: true);
						}
					}
					else
					{
						Preferences.SetShowHud(v: false);
					}
				}
				HotkeyRegistry.Poll();
				if (Preferences.ShowHud)
				{
					WindowManager.HandleInput();
				}
			}
			catch
			{
			}
		}

		public override void OnGUI()
		{
			if (_inWorld && Preferences.Enabled && Preferences.ShowHud)
			{
				WindowManager.Draw();
			}
		}

		public override void OnApplicationQuit()
		{
			LogHub.Uninstall();
		}

		public override void OnDeinitializeMelon()
		{
			LogHub.Uninstall();
		}
	}
	internal static class HotlineConsole
	{
		private static int _lastFrame = -1;

		private static string _lastSig = "";

		internal static bool TryHandle(string raw)
		{
			if (string.IsNullOrWhiteSpace(raw))
			{
				return false;
			}
			return Dispatch(raw.Trim().Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries));
		}

		internal static bool TryHandle(List<string> args)
		{
			if (args == null || args.Count == 0)
			{
				return false;
			}
			string[] array = new string[args.Count];
			for (int i = 0; i < args.Count; i++)
			{
				array[i] = args[i];
			}
			return Dispatch(array);
		}

		private static bool Dispatch(string[] p)
		{
			if (p.Length == 0 || !p[0].Equals("hotline", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			string text = string.Join(" ", p);
			int frameCount = Time.frameCount;
			if (frameCount == _lastFrame && text == _lastSig)
			{
				return true;
			}
			_lastFrame = frameCount;
			_lastSig = text;
			LogHub.Write("Console", 0, text);
			string text2 = ((p.Length > 1) ? p[1].ToLowerInvariant() : "panels");
			try
			{
				switch (text2)
				{
				case "hud":
					Hud(p);
					break;
				case "panels":
					PanelsList();
					break;
				case "panel":
					PanelCmd(p);
					break;
				case "act":
					ActCmd(p);
					break;
				case "toggle":
					ToggleCmd(p);
					break;
				case "log":
					LogCmd(p);
					break;
				case "keys":
					KeysList();
					break;
				case "intercept":
					Intercept(p);
					break;
				case "key":
					KeyCmd(p);
					break;
				case "help":
					Help();
					break;
				default:
					Log("unknown '" + text2 + "'. Try 'hotline help'.");
					break;
				}
			}
			catch (Exception ex)
			{
				Log("error: " + ex.Message);
			}
			return true;
		}

		private static void Help()
		{
			Log("commands: hud [on|off|move <x> <y>|font <n>|reset] | panels | panel <id> [on|off|move <x> <y>|size <w> <h>|reset] | act <actionId> | toggle <toggleId> [on|off] | log [<channel>|all] [n] | keys | intercept [on|off|status|suppress on|off] | key press <KeyCode> [mod] | key master <KeyCode>");
		}

		private static void Intercept(string[] p)
		{
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			string text = ((p.Length > 2) ? p[2].ToLowerInvariant() : "status");
			switch (text)
			{
			case "on":
			case "off":
				Preferences.SetInterceptFunctionKeys(text == "on");
				MelonPreferences.Save();
				Log("auto-interception = " + Preferences.InterceptFunctionKeys);
				return;
			case "suppress":
				Preferences.SetSuppressRawKeys(BoolArg(p, 3, !Preferences.SuppressRawKeys));
				MelonPreferences.Save();
				Log("suppress raw keys = " + Preferences.SuppressRawKeys);
				return;
			}
			Log($"auto-interception: pref={Preferences.InterceptFunctionKeys} suppressRaw={Preferences.SuppressRawKeys} patch={(Interceptor.Installed ? "installed" : "NOT installed")} postfixCalls={Interceptor.PostfixCalls}");
			IReadOnlyDictionary<KeyCode, HashSet<string>> owners = Interceptor.Owners;
			if (owners.Count == 0)
			{
				Log("  no mod function keys discovered yet.");
				return;
			}
			foreach (KeyValuePair<KeyCode, HashSet<string>> item in owners)
			{
				Log($"  {item.Key} <- {string.Join(", ", item.Value)}");
			}
		}

		private unsafe static void KeyCmd(string[] p)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: 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_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_00ab: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			string text = ((p.Length > 2) ? p[2].ToLowerInvariant() : null);
			if (text == "press" && p.Length > 3)
			{
				if (Enum.TryParse<KeyCode>(p[3], ignoreCase: true, out KeyCode result) && (int)result != 0)
				{
					if (p.Length > 4)
					{
						Interceptor.RequestPress(result, p[4]);
						Log($"queued synthetic press: {result} -> {p[4]}");
						return;
					}
					int num = 0;
					foreach (string item in Interceptor.ModsForKey(result))
					{
						Interceptor.RequestPress(result, item);
						num++;
					}
					Log((num > 0) ? $"queued synthetic press: {result} -> {num} mod(s)" : $"no mod polls {result} yet (nothing to press).");
				}
				else
				{
					Log("unknown key '" + p[3] + "' (use a UnityEngine.KeyCode name, e.g. F9).");
				}
			}
			else if (text == "master" && p.Length > 3)
			{
				if (Enum.TryParse<KeyCode>(p[3], ignoreCase: true, out KeyCode result2) && (int)result2 != 0)
				{
					Preferences.SetMasterKey(((object)(*(KeyCode*)(&result2))/*cast due to .constrained prefix*/).ToString());
					MelonPreferences.Save();
					Log("master overlay key = " + ((object)Preferences.MasterKey/*cast due to .constrained prefix*/).ToString());
				}
				else
				{
					Log("unknown key '" + p[3] + "' (use a UnityEngine.KeyCode name, e.g. F6).");
				}
			}
			else
			{
				Log("usage: hotline key press <KeyCode> | hotline key master <KeyCode>");
			}
		}

		private static void Hud(string[] p)
		{
			switch ((p.Length > 2) ? p[2].ToLowerInvariant() : null)
			{
			case "move":
				Preferences.SetHudPos(FloatArg(p, 3, Preferences.HudX), FloatArg(p, 4, Preferences.HudY));
				WindowLayout.Get("overview", 8f, 8f, 320f, 300f, dvis: true);
				WindowLayout.SetPos("overview", Preferences.HudX, Preferences.HudY);
				WindowLayout.Save();
				Log($"overview pos = {Preferences.HudX:F0},{Preferences.HudY:F0}");
				break;
			case "font":
				Preferences.SetHudFontSize((int)FloatArg(p, 3, Preferences.HudFontSize));
				MelonPreferences.Save();
				Log("overlay font = " + Preferences.HudFontSize);
				break;
			case "reset":
				Preferences.SetHudPos(8f, 8f);
				Preferences.SetHudFontSize(12);
				WindowLayout.Reset("overview");
				MelonPreferences.Save();
				Log("overlay reset (pos 8,8 font 12)");
				break;
			default:
			{
				bool num = BoolArg(p, 2, !Preferences.ShowHud);
				Preferences.SetShowHud(num);
				if (num)
				{
					WindowLayout.SetVisible("overview", v: true);
				}
				MelonPreferences.Save();
				Log("overlay = " + Preferences.ShowHud);
				break;
			}
			}
		}

		private static void PanelsList()
		{
			Log($"overview [{(WindowLayout.IsVisible("overview") ? "on" : "off")}]  timeline [{(WindowLayout.IsVisible("timeline") ? "on" : "off")}]");
			IReadOnlyList<PanelModel> all = PanelRegistry.All;
			if (all.Count == 0)
			{
				Log("no mod panels registered yet (enter the world; mods register on load).");
				return;
			}
			for (int i = 0; i < all.Count; i++)
			{
				PanelModel panelModel = all[i];
				Log($"  {panelModel.Id,-16} [{(WindowLayout.IsVisible(panelModel.Id) ? "on" : "off")}]  actions={panelModel.Actions.Count} toggles={panelModel.Toggles.Count} title=\"{panelModel.Title}\"");
			}
		}

		private static void PanelCmd(string[] p)
		{
			if (p.Length <= 2)
			{
				Log("usage: hotline panel <id> [on|off|move <x> <y>|size <w> <h>|reset]. 'hotline panels' lists ids.");
				return;
			}
			string text = p[2];
			switch ((p.Length > 3) ? p[3].ToLowerInvariant() : "on")
			{
			case "on":
				WindowLayout.SetVisible(text, v: true);
				Log("panel " + text + " = on");
				break;
			case "off":
				WindowLayout.SetVisible(text, v: false);
				Log("panel " + text + " = off");
				break;
			case "move":
				WindowLayout.Get(text, 8f, 8f, 320f, 240f, dvis: true);
				WindowLayout.SetPos(text, FloatArg(p, 4, 8f), FloatArg(p, 5, 8f));
				WindowLayout.Save();
				Log("panel " + text + " moved");
				break;
			case "size":
				WindowLayout.Get(text, 8f, 8f, 320f, 240f, dvis: true);
				WindowLayout.SetSize(text, FloatArg(p, 4, 320f), FloatArg(p, 5, 240f));
				WindowLayout.Save();
				Log("panel " + text + " resized");
				break;
			case "reset":
				WindowLayout.Reset(text);
				Log("panel " + text + " reset");
				break;
			default:
				Log("usage: hotline panel <id> [on|off|move <x> <y>|size <w> <h>|reset]");
				break;
			}
		}

		private static void ActCmd(string[] p)
		{
			if (p.Length <= 2)
			{
				Log("usage: hotline act <actionId> (see the panel; ids look like 'Siesta:force-cosmetic').");
			}
			else
			{
				Log(PanelRegistry.Invoke(p[2]) ? ("ran " + p[2]) : ("no action '" + p[2] + "'"));
			}
		}

		private static void ToggleCmd(string[] p)
		{
			if (p.Length <= 2)
			{
				Log("usage: hotline toggle <toggleId> [on|off] (omit to flip).");
				return;
			}
			string text = p[2];
			bool value = BoolArg(p, 3, !PanelRegistry.GetToggle(text));
			Log(PanelRegistry.SetToggle(text, value) ? $"{text} = {value}" : ("no toggle '" + text + "'"));
		}

		private static void LogCmd(string[] p)
		{
			string text = ((p.Length > 2) ? p[2] : "all");
			int n = IntArg(p, 3, 25);
			List<LogEntry> list = (text.Equals("all", StringComparison.OrdinalIgnoreCase) ? LogHub.Timeline(n) : LogHub.Channel(text, n));
			if (list.Count == 0)
			{
				Log($"log '{text}': no entries (channels: {string.Join(", ", LogHub.Channels())}).");
				return;
			}
			Log($"log '{text}' (last {list.Count}):");
			foreach (LogEntry item in list)
			{
				string value = ((item.Lvl == 2) ? "E" : ((item.Lvl == 1) ? "W" : "I"));
				Log($"  {item.Time} {value} [{item.Ch}] {item.Msg}");
			}
		}

		private static void KeysList()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//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_00cd: Unknown result type (might be due to invalid IL or missing references)
			IReadOnlyList<HotkeyBinding> all = HotkeyRegistry.All;
			if (all.Count == 0)
			{
				Log("no central hotkeys registered. Master overlay key = " + ((object)Preferences.MasterKey/*cast due to .constrained prefix*/).ToString() + ".");
				return;
			}
			Log($"central hotkeys (master overlay key = {Preferences.MasterKey}):");
			for (int i = 0; i < all.Count; i++)
			{
				HotkeyBinding hotkeyBinding = all[i];
				Log($"  {hotkeyBinding.Owner}:{hotkeyBinding.Label}  =  {(((int)hotkeyBinding.Key == 0) ? "(button only)" : ((object)Unsafe.As<KeyCode, KeyCode>(ref hotkeyBinding.Key)/*cast due to .constrained prefix*/).ToString())}");
			}
		}

		private static int IntArg(string[] p, int idx, int def)
		{
			if (p.Length > idx && int.TryParse(p[idx], out var result))
			{
				return result;
			}
			return def;
		}

		private static float FloatArg(string[] p, int idx, float def)
		{
			if (p.Length > idx && float.TryParse(p[idx], NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			return def;
		}

		private static bool BoolArg(string[] p, int idx, bool toggleDefault)
		{
			if (p.Length <= idx)
			{
				return toggleDefault;
			}
			switch (p[idx].ToLowerInvariant())
			{
			case "on":
			case "true":
			case "1":
			case "yes":
				return true;
			case "off":
			case "false":
			case "0":
			case "no":
				return false;
			default:
				return toggleDefault;
			}
		}

		internal static void Log(string msg)
		{
			Instance log = Core.Log;
			if (log != null)
			{
				log.Msg("[hotline] " + msg);
			}
			LogHub.Write("Hotline", 0, msg);
		}
	}
	[HarmonyPatch(typeof(Console), "SubmitCommand", new Type[] { typeof(string) })]
	internal static class Hotline_Console_SubmitCommand_String_Patch
	{
		private static bool Prefix(string args)
		{
			try
			{
				return !HotlineConsole.TryHandle(args);
			}
			catch
			{
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(Console), "SubmitCommand", new Type[] { typeof(List<string>) })]
	internal static class Hotline_Console_SubmitCommand_List_Patch
	{
		private static bool Prefix(List<string> args)
		{
			try
			{
				return !HotlineConsole.TryHandle(args);
			}
			catch
			{
				return true;
			}
		}
	}
}
namespace Hotline.UI
{
	internal sealed class WinState
	{
		public float X;

		public float Y;

		public float W;

		public float H;

		public bool Visible;
	}
	internal static class WindowLayout
	{
		private static readonly Dictionary<string, WinState> _map = new Dictionary<string, WinState>();

		private static readonly CultureInfo Inv = CultureInfo.InvariantCulture;

		private static bool _loaded;

		private static void EnsureLoaded()
		{
			if (!_loaded)
			{
				_loaded = true;
				Parse(Preferences.WindowLayouts);
			}
		}

		internal static WinState Get(string id, float dx, float dy, float dw, float dh, bool dvis)
		{
			EnsureLoaded();
			if (!_map.TryGetValue(id, out var value))
			{
				value = new WinState
				{
					X = dx,
					Y = dy,
					W = dw,
					H = dh,
					Visible = dvis
				};
				_map[id] = value;
			}
			return value;
		}

		internal static bool IsVisible(string id)
		{
			EnsureLoaded();
			if (_map.TryGetValue(id, out var value))
			{
				return value.Visible;
			}
			return false;
		}

		internal static void SetPos(string id, float x, float y)
		{
			if (_map.TryGetValue(id, out var value))
			{
				value.X = x;
				value.Y = y;
			}
		}

		internal static void SetSize(string id, float w, float h)
		{
			if (_map.TryGetValue(id, out var value))
			{
				value.W = w;
				value.H = h;
			}
		}

		internal static void SetVisible(string id, bool v)
		{
			EnsureLoaded();
			if (!_map.TryGetValue(id, out var value))
			{
				value = new WinState
				{
					X = 8f,
					Y = 8f,
					W = 360f,
					H = 280f
				};
				_map[id] = value;
			}
			value.Visible = v;
			Save();
		}

		internal static bool Toggle(string id)
		{
			bool flag = !IsVisible(id);
			SetVisible(id, flag);
			return flag;
		}

		internal static void Reset(string id)
		{
			EnsureLoaded();
			_map.Remove(id);
			Save();
		}

		internal static void Save()
		{
			Preferences.SetWindowLayouts(Serialize());
			MelonPreferences.Save();
		}

		private static void Parse(string s)
		{
			_map.Clear();
			if (string.IsNullOrWhiteSpace(s))
			{
				return;
			}
			string[] array = s.Split(';');
			foreach (string text in array)
			{
				if (string.IsNullOrWhiteSpace(text))
				{
					continue;
				}
				int num = text.IndexOf('=');
				if (num > 0)
				{
					string key = text.Substring(0, num).Trim();
					string[] array2 = text.Substring(num + 1).Split(',');
					if (array2.Length >= 5 && F(array2[0], out var v) && F(array2[1], out var v2) && F(array2[2], out var v3) && F(array2[3], out var v4))
					{
						_map[key] = new WinState
						{
							X = v,
							Y = v2,
							W = v3,
							H = v4,
							Visible = (array2[4].Trim() == "1")
						};
					}
				}
			}
		}

		private static string Serialize()
		{
			StringBuilder stringBuilder = new StringBuilder(128);
			bool flag = true;
			foreach (KeyValuePair<string, WinState> item in _map)
			{
				if (!flag)
				{
					stringBuilder.Append(';');
				}
				flag = false;
				WinState value = item.Value;
				stringBuilder.Append(item.Key).Append('=').Append(N(value.X))
					.Append(',')
					.Append(N(value.Y))
					.Append(',')
					.Append(N(value.W))
					.Append(',')
					.Append(N(value.H))
					.Append(',')
					.Append(value.Visible ? '1' : '0');
			}
			return stringBuilder.ToString();
		}

		private static bool F(string s, out float v)
		{
			return float.TryParse(s.Trim(), NumberStyles.Float, Inv, out v);
		}

		private static string N(float v)
		{
			return ((int)v).ToString(Inv);
		}
	}
	internal static class WindowManager
	{
		private struct Hit
		{
			public string Win;

			public Rect Rect;

			public int Type;

			public string Arg;
		}

		private enum Drag
		{
			None,
			Move,
			Resize
		}

		private const float TitleH = 20f;

		private const float Grip = 14f;

		private const float Pad = 6f;

		private const float Gap = 4f;

		private const float MinW = 160f;

		private const float MinH = 70f;

		private static float _btnH = 22f;

		private static bool _stylesReady;

		private static GUIStyle _bg;

		private static GUIStyle _title;

		private static GUIStyle _close;

		private static GUIStyle _grip;

		private static GUIStyle _text;

		private static GUIStyle _btn;

		private static Texture2D _bgTex;

		private static Texture2D _titleTex;

		private static Texture2D _whiteTex;

		private static Texture2D _gripTex;

		private static Vector2 _mouse;

		private static bool _cursorFree;

		private static readonly Color BtnNormal = new Color(0.3f, 0.32f, 0.38f, 0.98f);

		private static readonly Color BtnHover = new Color(0.44f, 0.47f, 0.56f, 0.98f);

		private static readonly Color BtnOn = new Color(0.36f, 0.4f, 0.8f, 0.98f);

		private static readonly Color BtnOnHover = new Color(0.47f, 0.51f, 0.92f, 0.98f);

		private static readonly Color BtnGreen = new Color(0.2f, 0.52f, 0.32f, 0.98f);

		private static readonly Color BtnGreenHover = new Color(0.28f, 0.64f, 0.42f, 0.98f);

		private static readonly Color BtnRed = new Color(0.6f, 0.27f, 0.31f, 0.98f);

		private static readonly Color BtnRedHover = new Color(0.73f, 0.35f, 0.39f, 0.98f);

		private static readonly Color TitleFront = new Color(0.97f, 0.98f, 1f);

		private static readonly Color TitleDim = new Color(0.6f, 0.62f, 0.7f);

		private static readonly Color TitleBarCol = new Color(0.12f, 0.13f, 0.2f, 0.99f);

		private static readonly List<string> _order = new List<string>();

		private static readonly Dictionary<string, float> _scroll = new Dictionary<string, float>();

		private static readonly Dictionary<string, Rect> _frameRects = new Dictionary<string, Rect>();

		private static readonly Dictionary<string, Rect> _titleRects = new Dictionary<string, Rect>();

		private static readonly Dictionary<string, Rect> _closeRects = new Dictionary<string, Rect>();

		private static readonly Dictionary<string, Rect> _gripRects = new Dictionary<string, Rect>();

		private static readonly Dictionary<string, Rect> _bodyRects = new Dictionary<string, Rect>();

		private static readonly Dictionary<string, float> _contentH = new Dictionary<string, float>();

		private static readonly List<Hit> _hits = new List<Hit>(32);

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

		private static float _nextText;

		private static Drag _drag = Drag.None;

		private static string _dragId;

		private static Vector2 _grab;

		private static Rect _startRect;

		internal static void Draw()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			EnsureStyles();
			int hudFontSize = Preferences.HudFontSize;
			GUIStyle text = _text;
			int fontSize = (_btn.fontSize = hudFontSize);
			text.fontSize = fontSize;
			_title.fontSize = hudFontSize;
			_btnH = Mathf.Max(22f, (float)hudFontSize + 10f);
			_cursorFree = (int)Cursor.lockState != 1;
			_mouse = new Vector2(Input.mousePosition.x, (float)Screen.height - Input.mousePosition.y);
			RefreshWindowList();
			MaybeRebuildText();
			_hits.Clear();
			_frameRects.Clear();
			_titleRects.Clear();
			_closeRects.Clear();
			_gripRects.Clear();
			_bodyRects.Clear();
			string text2 = null;
			for (int num2 = _order.Count - 1; num2 >= 0; num2--)
			{
				if (WindowLayout.IsVisible(_order[num2]))
				{
					text2 = _order[num2];
					break;
				}
			}
			for (int i = 0; i < _order.Count; i++)
			{
				string text3 = _order[i];
				if (WindowLayout.IsVisible(text3))
				{
					DrawWindow(text3, text3 == text2);
				}
			}
		}

		private static void RefreshWindowList()
		{
			WindowLayout.Get("overview", 8f, 8f, 320f, 300f, dvis: true);
			EnsureInOrder("overview");
			IReadOnlyList<PanelModel> all = PanelRegistry.All;
			for (int i = 0; i < all.Count; i++)
			{
				WindowLayout.Get(all[i].Id, 360f + (float)(i % 3) * 28f, 40f + (float)i * 34f, 320f, 240f, dvis: false);
				EnsureInOrder(all[i].Id);
			}
			WindowLayout.Get("timeline", 8f, 360f, 560f, 220f, dvis: false);
			EnsureInOrder("timeline");
		}

		private static void EnsureInOrder(string id)
		{
			if (!_order.Contains(id))
			{
				_order.Add(id);
			}
		}

		private static void DrawWindow(string id, bool isFront)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			WinState winState = WindowLayout.Get(id, 8f, 8f, 320f, 240f, dvis: false);
			float num = Mathf.Clamp(winState.W, 160f, (float)Screen.width);
			float num2 = Mathf.Clamp(winState.H, 70f, (float)Screen.height);
			float num3 = Mathf.Clamp(winState.X, 0f, Mathf.Max(0f, (float)Screen.width - num));
			float num4 = Mathf.Clamp(winState.Y, 0f, Mathf.Max(0f, (float)Screen.height - num2));
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(num3, num4, num, num2);
			_frameRects[id] = val;
			GUI.Box(val, GUIContent.none, _bg);
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(num3, num4, num, 20f);
			GUI.contentColor = (isFront ? TitleFront : TitleDim);
			GUI.Box(val2, "  " + TitleOf(id), _title);
			GUI.contentColor = Color.white;
			_titleRects[id] = val2;
			Rect val3 = default(Rect);
			((Rect)(ref val3))..ctor(((Rect)(ref val)).xMax - 20f, num4, 20f, 20f);
			GUI.backgroundColor = ((_cursorFree && ((Rect)(ref val3)).Contains(_mouse)) ? BtnRedHover : TitleBarCol);
			GUI.Box(val3, "x", _close);
			GUI.backgroundColor = Color.white;
			_closeRects[id] = val3;
			Rect val4 = default(Rect);
			((Rect)(ref val4))..ctor(num3 + 2f, num4 + 20f, num - 4f, num2 - 20f - 2f);
			_bodyRects[id] = val4;
			float scroll = GetScroll(id);
			float innerW = ((Rect)(ref val4)).width - 12f - 2f;
			GUI.BeginGroup(val4);
			float localY = 6f;
			DrawBody(id, innerW, scroll, val4, ref localY);
			GUI.EndGroup();
			float num5 = localY + 6f - 4f;
			_contentH[id] = num5;
			float num6 = Mathf.Max(0f, num5 - ((Rect)(ref val4)).height);
			if (scroll > num6)
			{
				_scroll[id] = num6;
			}
			Rect val5 = default(Rect);
			((Rect)(ref val5))..ctor(((Rect)(ref val)).xMax - 14f, ((Rect)(ref val)).yMax - 14f, 14f, 14f);
			GUI.Box(val5, GUIContent.none, _grip);
			_gripRects[id] = val5;
		}

		private static void DrawBody(string id, float innerW, float scroll, Rect bodyRect, ref float localY)
		{
			//IL_0019: 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_0036: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_01d3: Unknown result type (might be due to invalid IL or missing references)
			string text = KindOf(id);
			if (text == "overview")
			{
				Label(innerW, scroll, bodyRect, ref localY, "<b>Hotline</b>  -  toggle a mod's panel");
				IReadOnlyList<PanelModel> all = PanelRegistry.All;
				if (all.Count == 0)
				{
					Label(innerW, scroll, bodyRect, ref localY, "<color=#8a8f9e>no mod panels registered yet</color>");
				}
				for (int i = 0; i < all.Count; i++)
				{
					Button(id, innerW, scroll, bodyRect, ref localY, all[i].Title, 3, all[i].Id, WindowLayout.IsVisible(all[i].Id));
				}
				Button(id, innerW, scroll, bodyRect, ref localY, "Timeline (logs)", 3, "timeline", WindowLayout.IsVisible("timeline"));
				return;
			}
			if (text == "timeline")
			{
				Label(innerW, scroll, bodyRect, ref localY, Text("timeline"));
				return;
			}
			PanelModel panelModel = PanelRegistry.Get(id);
			if (panelModel == null)
			{
				Label(innerW, scroll, bodyRect, ref localY, "(panel gone)");
				return;
			}
			Label(innerW, scroll, bodyRect, ref localY, Text("panel:" + id));
			for (int j = 0; j < panelModel.Actions.Count; j++)
			{
				Button(id, innerW, scroll, bodyRect, ref localY, panelModel.Actions[j].Label, 1, panelModel.Actions[j].Id, on: false);
			}
			for (int k = 0; k < panelModel.Toggles.Count; k++)
			{
				bool toggle = PanelRegistry.GetToggle(panelModel.Toggles[k].Id);
				Button(id, innerW, scroll, bodyRect, ref localY, (toggle ? "[x] " : "[ ] ") + panelModel.Toggles[k].Label, 2, panelModel.Toggles[k].Id, toggle);
			}
			if (panelModel.HasLog)
			{
				Label(innerW, scroll, bodyRect, ref localY, Text("log:" + id));
			}
		}

		private static void Label(float innerW, float scroll, Rect bodyRect, ref float localY, string text)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrEmpty(text))
			{
				GUIContent val = new GUIContent(text);
				float num = _text.CalcHeight(val, innerW);
				float num2 = localY - scroll;
				if (num2 + num > 0f && num2 < ((Rect)(ref bodyRect)).height)
				{
					GUI.Label(new Rect(6f, num2, innerW, num), val, _text);
				}
				localY += num + 4f;
			}
		}

		private static void Button(string id, float innerW, float scroll, Rect bodyRect, ref float localY, string label, int type, string arg, bool on, int accent = 0)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_000d: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Min(innerW, _btn.CalcSize(new GUIContent(label)).x + 16f);
			float num2 = localY - scroll;
			if (num2 + _btnH > 0f && num2 < ((Rect)(ref bodyRect)).height)
			{
				Rect rect = default(Rect);
				((Rect)(ref rect))..ctor(((Rect)(ref bodyRect)).x + 6f, ((Rect)(ref bodyRect)).y + num2, num, _btnH);
				bool hover = _cursorFree && ((Rect)(ref rect)).Contains(_mouse);
				GUI.backgroundColor = ButtonColor(on, accent, hover);
				GUI.Box(new Rect(6f, num2, num, _btnH), label, _btn);
				GUI.backgroundColor = Color.white;
				_hits.Add(new Hit
				{
					Win = id,
					Rect = rect,
					Type = type,
					Arg = arg
				});
			}
			localY += _btnH + 4f;
		}

		private static Color ButtonColor(bool on, int accent, bool hover)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_0019: 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_003b: 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)
			if (on)
			{
				if (!hover)
				{
					return BtnOn;
				}
				return BtnOnHover;
			}
			switch (accent)
			{
			case 1:
				if (!hover)
				{
					return BtnGreen;
				}
				return BtnGreenHover;
			case 2:
				if (!hover)
				{
					return BtnRed;
				}
				return BtnRedHover;
			default:
				if (!hover)
				{
					return BtnNormal;
				}
				return BtnHover;
			}
		}

		internal static void HandleInput()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0011: 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_0031: 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_009b: 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_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: 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_0193: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Cursor.lockState == 1)
			{
				_drag = Drag.None;
				return;
			}
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(Input.mousePosition.x, (float)Screen.height - Input.mousePosition.y);
			float y = Input.mouseScrollDelta.y;
			if (Mathf.Abs(y) > 0.01f)
			{
				string text = TopWindowAt(val, bodyOnly: true);
				if (text != null)
				{
					float num = Mathf.Max(0f, GetContentH(text) - GetBodyH(text));
					_scroll[text] = Mathf.Clamp(GetScroll(text) - y * 28f, 0f, num);
				}
			}
			if (Input.GetMouseButtonDown(0))
			{
				string text2 = TopWindowAt(val, bodyOnly: false);
				if (text2 == null)
				{
					return;
				}
				BringToFront(text2);
				if (_closeRects.TryGetValue(text2, out var value) && ((Rect)(ref value)).Contains(val))
				{
					WindowLayout.SetVisible(text2, v: false);
					return;
				}
				if (_gripRects.TryGetValue(text2, out var value2) && ((Rect)(ref value2)).Contains(val))
				{
					_drag = Drag.Resize;
					_dragId = text2;
					_grab = val;
					_startRect = _frameRects[text2];
					return;
				}
				if (_titleRects.TryGetValue(text2, out var value3) && ((Rect)(ref value3)).Contains(val))
				{
					_drag = Drag.Move;
					_dragId = text2;
					Rect val2 = _frameRects[text2];
					_grab = val - new Vector2(((Rect)(ref val2)).x, ((Rect)(ref val2)).y);
					return;
				}
				for (int i = 0; i < _hits.Count; i++)
				{
					Hit hit = _hits[i];
					if (!(hit.Win != text2) && ((Rect)(ref hit.Rect)).Contains(val))
					{
						switch (hit.Type)
						{
						case 1:
							PanelRegistry.Invoke(hit.Arg);
							break;
						case 2:
							PanelRegistry.SetToggle(hit.Arg, !PanelRegistry.GetToggle(hit.Arg));
							break;
						case 3:
							WindowLayout.Toggle(hit.Arg);
							break;
						}
						break;
					}
				}
			}
			else if (Input.GetMouseButton(0) && _drag != Drag.None)
			{
				if (_drag == Drag.Move)
				{
					WindowLayout.SetPos(_dragId, val.x - _grab.x, val.y - _grab.y);
				}
				else
				{
					WindowLayout.SetSize(_dragId, Mathf.Max(160f, ((Rect)(ref _startRect)).width + (val.x - _grab.x)), Mathf.Max(70f, ((Rect)(ref _startRect)).height + (val.y - _grab.y)));
				}
			}
			else if (Input.GetMouseButtonUp(0) && _drag != Drag.None)
			{
				_drag = Drag.None;
				WindowLayout.Save();
			}
		}

		private static string TopWindowAt(Vector2 m, bool bodyOnly)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			for (int num = _order.Count - 1; num >= 0; num--)
			{
				string text = _order[num];
				if (WindowLayout.IsVisible(text) && (bodyOnly ? _bodyRects : _frameRects).TryGetValue(text, out var value) && ((Rect)(ref value)).Contains(m))
				{
					return text;
				}
			}
			return null;
		}

		private static void BringToFront(string id)
		{
			if (_order.Remove(id))
			{
				_order.Add(id);
			}
		}

		private static void MaybeRebuildText()
		{
			if (Time.unscaledTime < _nextText)
			{
				return;
			}
			_nextText = Time.unscaledTime + 0.1f;
			IReadOnlyList<PanelModel> all = PanelRegistry.All;
			for (int i = 0; i < all.Count; i++)
			{
				PanelModel panelModel = all[i];
				_textCache["panel:" + panelModel.Id] = BuildPanelText(panelModel);
				if (panelModel.HasLog)
				{
					_textCache["log:" + panelModel.Id] = BuildLogText(panelModel.Id, 16);
				}
			}
			_textCache["timeline"] = BuildTimelineText(220);
		}

		private static string Text(string key)
		{
			if (!_textCache.TryGetValue(key, out var value))
			{
				return "";
			}
			return value;
		}

		private static string BuildPanelText(PanelModel p)
		{
			StringBuilder stringBuilder = new StringBuilder(256);
			for (int i = 0; i < p.Texts.Count; i++)
			{
				string text = null;
				try
				{
					text = p.Texts[i]?.Invoke();
				}
				catch
				{
				}
				if (!string.IsNullOrEmpty(text))
				{
					Line(stringBuilder, text);
				}
			}
			return stringBuilder.ToString();
		}

		private static string BuildLogText(string channel, int n)
		{
			List<LogEntry> list = LogHub.Channel(channel, n);
			if (list.Count == 0)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder(256);
			Line(stringBuilder, "<b>log</b>");
			for (int i = 0; i < list.Count; i++)
			{
				AppendLogLine(stringBuilder, list[i], withChannel: false);
			}
			return stringBuilder.ToString();
		}

		private static string BuildTimelineText(int n)
		{
			List<LogEntry> list = LogHub.Timeline(n);
			if (list.Count == 0)
			{
				return "(no log output yet)";
			}
			StringBuilder stringBuilder = new StringBuilder(1024);
			for (int i = 0; i < list.Count; i++)
			{
				AppendLogLine(stringBuilder, list[i], withChannel: true);
			}
			return stringBuilder.ToString();
		}

		private static void AppendLogLine(StringBuilder sb, LogEntry e, bool withChannel)
		{
			if (sb.Length > 0)
			{
				sb.Append('\n');
			}
			string value = ((e.Lvl == 2) ? "#f55" : ((e.Lvl == 1) ? "#fd5" : "#cdd6f4"));
			sb.Append("<color=").Append(value).Append('>')
				.Append(e.Time)
				.Append(' ');
			if (withChannel)
			{
				sb.Append('[').Append(e.Ch).Append("] ");
			}
			sb.Append(e.Msg).Append("</color>");
		}

		private static void Line(StringBuilder sb, string s)
		{
			if (sb.Length > 0)
			{
				sb.Append('\n');
			}
			sb.Append(s);
		}

		private static string KindOf(string id)
		{
			if (!(id == "overview"))
			{
				if (!(id == "timeline"))
				{
					return "panel";
				}
				return "timeline";
			}
			return "overview";
		}

		private static string TitleOf(string id)
		{
			if (id == "overview")
			{
				return "Hotline";
			}
			if (id == "timeline")
			{
				return "Timeline (all logs)";
			}
			PanelModel panelModel = PanelRegistry.Get(id);
			if (panelModel == null)
			{
				return id;
			}
			return panelModel.Title;
		}

		private static float GetScroll(string id)
		{
			if (!_scroll.TryGetValue(id, out var value))
			{
				return 0f;
			}
			return value;
		}

		private static float GetContentH(string id)
		{
			if (!_contentH.TryGetValue(id, out var value))
			{
				return 0f;
			}
			return value;
		}

		private static float GetBodyH(string id)
		{
			if (!_bodyRects.TryGetValue(id, out var value))
			{
				return 0f;
			}
			return ((Rect)(ref value)).height;
		}

		private static void EnsureStyles()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_009f: Expected O, but got Unknown
			//IL_00bd: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_0109: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: 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_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Expected O, but got Unknown
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Expected O, but got Unknown
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			if (!_stylesReady)
			{
				_stylesReady = true;
				_bgTex = Solid(new Color(0.055f, 0.065f, 0.085f, 0.93f));
				_titleTex = Solid(new Color(0.12f, 0.13f, 0.2f, 0.99f));
				_whiteTex = Solid(Color.white);
				_gripTex = Solid(new Color(0.45f, 0.48f, 0.85f, 0.9f));
				_bg = new GUIStyle
				{
					padding = new RectOffset(0, 0, 0, 0)
				};
				_bg.normal.background = _bgTex;
				_title = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)3,
					fontStyle = (FontStyle)1,
					richText = true
				};
				_title.normal.background = _titleTex;
				_title.normal.textColor = new Color(0.9f, 0.92f, 1f);
				_close = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontStyle = (FontStyle)1
				};
				_close.normal.background = _whiteTex;
				_close.normal.textColor = new Color(1f, 0.78f, 0.78f);
				_grip = new GUIStyle();
				_grip.normal.background = _gripTex;
				_text = new GUIStyle(GUI.skin.label)
				{
					richText = true,
					wordWrap = true,
					alignment = (TextAnchor)0
				};
				_text.normal.textColor = new Color(0.84f, 0.87f, 0.93f);
				_btn = new GUIStyle
				{
					alignment = (TextAnchor)4,
					richText = true,
					clipping = (TextClipping)0,
					padding = new RectOffset(6, 6, 2, 2),
					wordWrap = false
				};
				_btn.normal.background = _whiteTex;
				_btn.normal.textColor = Color.white;
			}
		}

		private static Texture2D Solid(Color c)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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)
			//IL_001f: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, c);
			val.Apply();
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}
	}
}
namespace Hotline.Panels
{
	internal sealed class ActionItem
	{
		public string Id;

		public string Label;

		public Action Run;
	}
	internal sealed class ToggleItem
	{
		public string Id;

		public string Label;

		public Func<bool> Get;

		public Action<bool> Set;
	}
	internal sealed class PanelModel
	{
		public string Id;

		public string Title;

		public bool HasLog;

		public readonly List<Func<string>> Texts = new List<Func<string>>(2);

		public readonly List<ActionItem> Actions = new List<ActionItem>(4);

		public readonly List<ToggleItem> Toggles = new List<ToggleItem>(4);
	}
	internal static class PanelRegistry
	{
		private static readonly List<PanelModel> _panels = new List<PanelModel>(8);

		private static readonly Dictionary<string, PanelModel> _byId = new Dictionary<string, PanelModel>(8);

		private static readonly Dictionary<string, ActionItem> _actions = new Dictionary<string, ActionItem>(16);

		private static readonly Dictionary<string, ToggleItem> _toggles = new Dictionary<string, ToggleItem>(16);

		internal static IReadOnlyList<PanelModel> All => _panels;

		internal static int Count => _panels.Count;

		internal static PanelModel GetOrCreate(string id, string title)
		{
			if (string.IsNullOrEmpty(id))
			{
				id = "misc";
			}
			if (!_byId.TryGetValue(id, out var value))
			{
				value = new PanelModel
				{
					Id = id,
					Title = (string.IsNullOrEmpty(title) ? id : title)
				};
				_byId[id] = value;
				_panels.Add(value);
			}
			else if (!string.IsNullOrEmpty(title))
			{
				value.Title = title;
			}
			return value;
		}

		internal static PanelModel Get(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return null;
			}
			_byId.TryGetValue(id, out var value);
			return value;
		}

		internal static void RegisterPanel(string id, string title)
		{
			GetOrCreate(id, title);
		}

		internal static void RegisterText(string panelId, Func<string> provider)
		{
			if (provider != null)
			{
				GetOrCreate(panelId, null).Texts.Add(provider);
			}
		}

		internal static void RegisterAction(string panelId, string actionId, string label, Action run)
		{
			if (run != null && !string.IsNullOrEmpty(actionId))
			{
				PanelModel orCreate = GetOrCreate(panelId, null);
				ActionItem actionItem = new ActionItem
				{
					Id = actionId,
					Label = (label ?? actionId),
					Run = run
				};
				orCreate.Actions.RemoveAll((ActionItem a) => a.Id == actionId);
				orCreate.Actions.Add(actionItem);
				_actions[actionId] = actionItem;
			}
		}

		internal static void RegisterToggle(string panelId, string toggleId, string label, Func<bool> get, Action<bool> set)
		{
			if (get != null && set != null && !string.IsNullOrEmpty(toggleId))
			{
				PanelModel orCreate = GetOrCreate(panelId, null);
				ToggleItem toggleItem = new ToggleItem
				{
					Id = toggleId,
					Label = (label ?? toggleId),
					Get = get,
					Set = set
				};
				orCreate.Toggles.RemoveAll((ToggleItem t) => t.Id == toggleId);
				orCreate.Toggles.Add(toggleItem);
				_toggles[toggleId] = toggleItem;
			}
		}

		internal static void BindPanelLog(string panelId)
		{
			GetOrCreate(panelId, null).HasLog = true;
		}

		internal static bool Invoke(string actionId)
		{
			if (string.IsNullOrEmpty(actionId) || !_actions.TryGetValue(actionId, out var value))
			{
				return false;
			}
			try
			{
				value.Run?.Invoke();
			}
			catch (Exception ex)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("[hotline] action '" + actionId + "' threw: " + ex.Message);
				}
			}
			return true;
		}

		internal static bool SetToggle(string toggleId, bool value)
		{
			if (string.IsNullOrEmpty(toggleId) || !_toggles.TryGetValue(toggleId, out var value2))
			{
				return false;
			}
			try
			{
				value2.Set?.Invoke(value);
			}
			catch (Exception ex)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("[hotline] toggle '" + toggleId + "' threw: " + ex.Message);
				}
			}
			return true;
		}

		internal static bool GetToggle(string toggleId)
		{
			if (!string.IsNullOrEmpty(toggleId) && _toggles.TryGetValue(toggleId, out var value))
			{
				try
				{
					return value.Get != null && value.Get();
				}
				catch
				{
				}
			}
			return false;
		}
	}
}
namespace Hotline.Logging
{
	internal struct LogEntry
	{
		public long Seq;

		public string Ch;

		public int Lvl;

		public string Msg;

		public string Time;
	}
	internal static class LogHub
	{
		private const int PerChannelMax = 400;

		private const int TimelineMax = 1200;

		private static readonly object _lock = new object();

		private static readonly Dictionary<string, Queue<LogEntry>> _channels = new Dictionary<string, Queue<LogEntry>>();

		private static readonly Queue<LogEntry> _timeline = new Queue<LogEntry>(1200);

		private static long _seq;

		internal static void Install()
		{
		}

		internal static void Uninstall()
		{
		}

		internal static void Write(string channel, int lvl, string msg)
		{
			if (string.IsNullOrEmpty(msg))
			{
				return;
			}
			if (string.IsNullOrEmpty(channel))
			{
				channel = "misc";
			}
			if (lvl < 0)
			{
				lvl = 0;
			}
			else if (lvl > 2)
			{
				lvl = 2;
			}
			lock (_lock)
			{
				LogEntry item = new LogEntry
				{
					Seq = ++_seq,
					Ch = channel,
					Lvl = lvl,
					Msg = msg,
					Time = DateTime.Now.ToString("HH:mm:ss")
				};
				if (!_channels.TryGetValue(channel, out var value))
				{
					value = new Queue<LogEntry>(64);
					_channels[channel] = value;
				}
				value.Enqueue(item);
				while (value.Count > 400)
				{
					value.Dequeue();
				}
				_timeline.Enqueue(item);
				while (_timeline.Count > 1200)
				{
					_timeline.Dequeue();
				}
			}
		}

		internal static List<LogEntry> Timeline(int n)
		{
			lock (_lock)
			{
				return TakeLast(_timeline, n);
			}
		}

		internal static List<LogEntry> Channel(string channel, int n)
		{
			lock (_lock)
			{
				Queue<LogEntry> value;
				return _channels.TryGetValue(channel, out value) ? TakeLast(value, n) : new List<LogEntry>();
			}
		}

		internal static List<string> Channels()
		{
			lock (_lock)
			{
				return new List<string>(_channels.Keys);
			}
		}

		internal static void Clear()
		{
			lock (_lock)
			{
				_channels.Clear();
				_timeline.Clear();
			}
		}

		private static List<LogEntry> TakeLast(Queue<LogEntry> q, int n)
		{
			if (n <= 0 || n >= q.Count)
			{
				return new List<LogEntry>(q);
			}
			List<LogEntry> list = new List<LogEntry>(q);
			return list.GetRange(list.Count - n, n);
		}
	}
}
namespace Hotline.Hotkeys
{
	internal sealed class HotkeyBinding
	{
		public string Owner;

		public string Label;

		public KeyCode Key;

		public Action Run;
	}
	internal static class HotkeyRegistry
	{
		private static readonly List<HotkeyBinding> _binds = new List<HotkeyBinding>(16);

		internal static IReadOnlyList<HotkeyBinding> All => _binds;

		internal static void Register(string owner, string label, KeyCode key, Action run)
		{
			//IL_0045: 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_013f: 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_0064: 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)
			if (run == null || string.IsNullOrEmpty(label))
			{
				return;
			}
			owner = (string.IsNullOrEmpty(owner) ? "misc" : owner);
			if ((int)key != 0)
			{
				for (int i = 0; i < _binds.Count; i++)
				{
					HotkeyBinding hotkeyBinding = _binds[i];
					if (hotkeyBinding.Key == key && hotkeyBinding.Owner != owner)
					{
						Instance log = Core.Log;
						if (log != null)
						{
							log.Warning($"[hotline] hotkey conflict: {key} is bound by both '{hotkeyBinding.Owner}' and '{owner}' - both will fire.");
						}
					}
				}
			}
			_binds.RemoveAll((HotkeyBinding b) => b.Owner == owner && b.Label == label);
			_binds.Add(new HotkeyBinding
			{
				Owner = owner,
				Label = label,
				Key = key,
				Run = run
			});
		}

		internal static void Poll()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < _binds.Count; i++)
			{
				HotkeyBinding hotkeyBinding = _binds[i];
				if ((int)hotkeyBinding.Key == 0 || !Input.GetKeyDown(hotkeyBinding.Key))
				{
					continue;
				}
				try
				{
					hotkeyBinding.Run?.Invoke();
				}
				catch (Exception ex)
				{
					Instance log = Core.Log;
					if (log != null)
					{
						log.Warning($"[hotline] hotkey '{hotkeyBinding.Owner}:{hotkeyBinding.Label}' threw: {ex.Message}");
					}
				}
			}
		}
	}
	internal static class Interceptor
	{
		private static bool _installed;

		private static bool _failed;

		private static readonly Assembly _selfAsm = typeof(Interceptor).Assembly;

		[ThreadStatic]
		private static string _currentOwner;

		private static readonly Dictionary<MethodBase, string> _ownerOf = new Dictionary<MethodBase, string>();

		private static readonly Dictionary<KeyCode, HashSet<string>> _owners = new Dictionary<KeyCode, HashSet<string>>();

		private static readonly Dictionary<(KeyCode key, string mod), int> _inject = new Dictionary<(KeyCode, string), int>();

		internal static long PostfixCalls;

		private static readonly KeyCode[] Targets;

		private static readonly string[] Lifecycle;

		private static int _lastSummonFrame;

		internal static bool Installed
		{
			get
			{
				if (_installed)
				{
					return !_failed;
				}
				return false;
			}
		}

		internal static IReadOnlyDictionary<KeyCode, HashSet<string>> Owners => _owners;

		private static bool IsTarget(KeyCode k)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between I4 and Unknown
			for (int i = 0; i < Targets.Length; i++)
			{
				if ((int)Targets[i] == (int)k)
				{
					return true;
				}
			}
			return false;
		}

		internal static void Install(Harmony h)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			//IL_017f: Expected O, but got Unknown
			if (_installed || _failed || h == null)
			{
				return;
			}
			try
			{
				MethodInfo method = typeof(Input).GetMethod("GetKeyDown", new Type[1] { typeof(KeyCode) });
				if (method == null)
				{
					_failed = true;
					Instance log = Core.Log;
					if (log != null)
					{
						log.Warning("[hotline] interceptor: Input.GetKeyDown(KeyCode) not found - auto-interception disabled.");
					}
					return;
				}
				h.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Interceptor), "GetKeyDownPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				MethodInfo methodInfo = AccessTools.Method(typeof(Interceptor), "OwnerPre", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Interceptor), "OwnerFin", (Type[])null, (Type[])null);
				foreach (MelonMod item in RegisteredMods())
				{
					if (item == null)
					{
						continue;
					}
					Type type = ((object)item).GetType();
					if (type.Assembly == _selfAsm)
					{
						continue;
					}
					string value = NameOf(item);
					for (int i = 0; i < Lifecycle.Length; i++)
					{
						MethodInfo method2 = type.GetMethod(Lifecycle[i], BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
						if (method2 == null || method2.IsAbstract || method2.DeclaringType == typeof(MelonMod) || _ownerOf.ContainsKey(method2))
						{
							continue;
						}
						try
						{
							h.Patch((MethodBase)method2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null);
							_ownerOf[method2] = value;
						}
						catch (Exception ex)
						{
							Instance log2 = Core.Log;
							if (log2 != null)
							{
								log2.Warning($"[hotline] wrap {value}.{Lifecycle[i]} failed: {ex.Message}");
							}
						}
					}
				}
				_installed = true;
				Instance log3 = Core.Log;
				if (log3 != null)
				{
					log3.Msg($"[hotline] auto-interception installed (Input.GetKeyDown + {_ownerOf.Count} mod lifecycle hooks).");
				}
			}
			catch (Exception ex2)
			{
				_failed = true;
				Instance log4 = Core.Log;
				if (log4 != null)
				{
					log4.Warning("[hotline] interceptor patch failed (auto-interception disabled, game unaffected): " + ex2.Message);
				}
			}
		}

		private static void OwnerPre(MethodBase __originalMethod, out string __state)
		{
			__state = _currentOwner;
			_ownerOf.TryGetValue(__originalMethod, out var value);
			_currentOwner = value;
		}

		private static void OwnerFin(string __state)
		{
			_currentOwner = __state;
		}

		private static void GetKeyDownPostfix(KeyCode __0, ref bool __result)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0066: 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)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_failed || !Preferences.InterceptFunctionKeys || !IsTarget(__0))
				{
					return;
				}
				PostfixCalls++;
				string currentOwner = _currentOwner;
				if (string.IsNullOrEmpty(currentOwner))
				{
					return;
				}
				if (!_owners.TryGetValue(__0, out var value))
				{
					value = new HashSet<string>();
					_owners[__0] = value;
				}
				if (value.Add(currentOwner))
				{
					Discovered(currentOwner, __0);
				}
				(KeyCode, string) key = (__0, currentOwner);
				if (_inject.TryGetValue(key, out var value2))
				{
					if (Time.frameCount - value2 <= 20)
					{
						__result = true;
						_inject.Remove(key);
						return;
					}
					_inject.Remove(key);
				}
				if (__result)
				{
					if (__0 == Preferences.MasterKey)
					{
						__result = false;
					}
					else if (Preferences.SuppressRawKeys)
					{
						Summon(currentOwner);
						__result = false;
					}
				}
			}
			catch
			{
			}
		}

		internal static void RequestPress(KeyCode key, string mod)
		{
			//IL_0000: 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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			if ((int)key != 0 && !string.IsNullOrEmpty(mod))
			{
				_inject[(key, mod)] = Time.frameCount;
				Instance log = Core.Log;
				if (log != null)
				{
					log.Msg($"[hotline] synthetic press queued: {key} -> {mod}");
				}
				LogHub.Write("Hotline", 0, $"press {key} ({mod})");
			}
		}

		internal static IEnumerable<string> ModsForKey(KeyCode key)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (!_owners.TryGetValue(key, out var value))
			{
				return Array.Empty<string>();
			}
			return value;
		}

		private unsafe static void Discovered(string mod, KeyCode key)
		{
			//IL_0007: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			PanelRegistry.RegisterPanel(mod, null);
			string actionId = mod + ":key-" + ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
			PanelRegistry.RegisterAction(mod, actionId, "Press " + ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(), delegate
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				RequestPress(key, mod);
			});
			Instance log = Core.Log;
			if (log != null)
			{
				log.Msg($"[hotline] discovered hotkey {key} polled by '{mod}' -> added a button to its overlay panel.");
			}
			LogHub.Write("Hotline", 0, $"discovered {key} ({mod})");
		}

		private static void Summon(string mod)
		{
			if (Time.frameCount == _lastSummonFrame)
			{
				return;
			}
			_lastSummonFrame = Time.frameCount;
			try
			{
				Preferences.SetShowHud(v: true);
				WindowLayout.SetVisible("overview", v: true);
				WindowLayout.SetVisible(mod, v: true);
			}
			catch
			{
			}
		}

		private static string NameOf(MelonMod mod)
		{
			try
			{
				MelonInfoAttribute info = ((MelonBase)mod).Info;
				string text = ((info != null) ? info.Name : null);
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			catch
			{
			}
			return ((object)mod).GetType().Namespace ?? ((object)mod).GetType().Name;
		}

		private static IEnumerable<MelonMod> RegisteredMods()
		{
			try
			{
				if (MelonTypeBase<MelonMod>.RegisteredMelons != null)
				{
					return MelonTypeBase<MelonMod>.RegisteredMelons;
				}
			}
			catch
			{
			}
			Type[] array = new Type[2]
			{
				typeof(MelonMod),
				typeof(MelonBase)
			};
			foreach (Type type in array)
			{
				try
				{
					if (type.GetProperty("RegisteredMelons", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) is IEnumerable<MelonMod> result)
					{
						return result;
					}
				}
				catch
				{
				}
			}
			return Array.Empty<MelonMod>();
		}

		static Interceptor()
		{
			KeyCode[] array = new KeyCode[12];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			Targets = (KeyCode[])(object)array;
			Lifecycle = new string[3] { "OnUpdate", "OnLateUpdate", "OnFixedUpdate" };
			_lastSummonFrame = -1;
		}
	}
}
namespace Hotline.Config
{
	internal static class Preferences
	{
		private const string CategoryId = "Hotline_01_Main";

		private static MelonPreferences_Category _category;

		private static MelonPreferences_Entry<bool> _enabled;

		private static MelonPreferences_Entry<bool> _showHud;

		private static MelonPreferences_Entry<string> _masterKey;

		private static MelonPreferences_Entry<int> _hudFontSize;

		private static MelonPreferences_Entry<float> _hudX;

		private static MelonPreferences_Entry<float> _hudY;

		private static MelonPreferences_Entry<string> _windowLayouts;

		private static MelonPreferences_Entry<bool> _interceptKeys;

		private static MelonPreferences_Entry<bool> _suppressRawKeys;

		internal static bool Enabled => _enabled?.Value ?? true;

		internal static bool ShowHud => _showHud?.Value ?? false;

		internal static KeyCode MasterKey
		{
			get
			{
				//IL_0025: 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)
				string value = _masterKey?.Value;
				if (string.IsNullOrEmpty(value) || !Enum.TryParse<KeyCode>(value, ignoreCase: true, out KeyCode result) || (int)result == 0)
				{
					return (KeyCode)287;
				}
				return result;
			}
		}

		internal static int HudFontSize => Mathf.Clamp(_hudFontSize?.Value ?? 12, 8, 32);

		internal static float HudX => _hudX?.Value ?? 8f;

		internal static float HudY => _hudY?.Value ?? 8f;

		internal static string WindowLayouts => _windowLayouts?.Value ?? "";

		internal static bool InterceptFunctionKeys => _interceptKeys?.Value ?? true;

		internal static bool SuppressRawKeys => _suppressRawKeys?.Value ?? false;

		internal static void Initialize()
		{
			if (_category == null)
			{
				_category = MelonPreferences.CreateCategory("Hotline_01_Main", "Hotline (Mod HUD & Hotkey Hub)");
				_enabled = Create("Enabled", def: true, "Enable Hotline", "Master switch. When OFF, Hotline does nothing at all. When ON, the unified overlay and the central hotkey table are available; the overlay stays hidden until you press the master key.");
				_showHud = Create("ShowHud", def: false, "Show overlay", "Whether the Hotline overlay is currently visible. Toggle live with the master key (default F7) or 'hotline hud'. Off by default.");
				_masterKey = Create("MasterHotkey", "F6", "Master overlay key", "The single key that opens/closes the Hotline overlay - the one hotkey that replaces every mod's own. Any UnityEngine.KeyCode name (e.g. F6, F4, Backslash). Defaults to F6. This key is reserved for Hotline and is never auto-intercepted.");
				_hudFontSize = Create("HudFontSize", 12, "Overlay font size", "On-screen overlay text size (px). The windows auto-resize to fit. Clamped 8-32. Change live with 'hotline hud font <n>' or by dragging a window's bottom-right corner.", (ValueValidator)(object)new ValueRange<int>(8, 32));
				_hudX = Create("HudX", 8f, "Overview position X", "Overview window left edge in pixels. Kept on-screen automatically. Change live with 'hotline hud move <x> <y>' or by dragging.", (ValueValidator)(object)new ValueRange<float>(0f, 4000f));
				_hudY = Create("HudY", 8f, "Overview position Y", "Overview window top edge in pixels. Kept on-screen automatically. Change live with 'hotline hud move <x> <y>' or by dragging.", (ValueValidator)(object)new ValueRange<float>(0f, 4000f));
				_windowLayouts = Create("WindowLayouts", "", "Overlay window layouts (managed)", "Internal: saved positions, sizes and visibility of the overlay windows (the overview, every mod's panel and the log timeline). Managed by dragging the windows or the 'hotline panel ...' console - you normally do not edit this by hand.");
				_interceptKeys = Create("InterceptFunctionKeys", def: true, "Auto-intercept mod function keys", "ON (default): detect other mods that bind function keys (F1-F12), attribute each to the mod, and add it to the overlay as a clickable button - so you can trigger any mod's hotkey from one place. Only the polling mod ever receives the synthetic press; vanilla input is never touched. Turn OFF to disable.");
				_suppressRawKeys = Create("SuppressRawFunctionKeys", def: false, "Take over raw function keys", "OFF (default): mods' function keys keep working normally; Hotline only ADDS a clickable button for each discovered key in the overlay. ON: a physical function-key press no longer reaches the mod - instead it opens this overlay focused on that mod's panel, where each of its keys is a button you click. Turn ON to stop two mods from fighting over the same key (the aggressive 'full takeover' mode).");
			}
		}

		private static MelonPreferences_Entry<T> Create<T>(string id, T def, string name, string desc = null, ValueValidator validator = null)
		{
			if (validator != null)
			{
				return _category.CreateEntry<T>(id, def, name, desc, false, false, validator);
			}
			return _category.CreateEntry<T>(id, def, name, desc, false, false, (ValueValidator)null, (string)null);
		}

		internal static void SetShowHud(bool v)
		{
			if (_showHud != null)
			{
				_showHud.Value = v;
			}
		}

		internal unsafe static void SetMasterKey(string name)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (_masterKey != null && !string.IsNullOrEmpty(name) && Enum.TryParse<KeyCode>(name, ignoreCase: true, out KeyCode result) && (int)result != 0)
			{
				_masterKey.Value = ((object)(*(KeyCode*)(&result))/*cast due to .constrained prefix*/).ToString();
			}
		}

		internal static void SetHudFontSize(int v)
		{
			if (_hudFontSize != null)
			{
				_hudFontSize.Value = Mathf.Clamp(v, 8, 32);
			}
		}

		internal static void SetHudPos(float x, float y)
		{
			if (_hudX != null)
			{
				_hudX.Value = x;
			}
			if (_hudY != null)
			{
				_hudY.Value = y;
			}
		}

		internal static void SetWindowLayouts(string v)
		{
			if (_windowLayouts != null)
			{
				_windowLayouts.Value = v ?? "";
			}
		}

		internal static void SetInterceptFunctionKeys(bool v)
		{
			if (_interceptKeys != null)
			{
				_interceptKeys.Value = v;
			}
		}

		internal static void SetSuppressRawKeys(bool v)
		{
			if (_suppressRawKeys != null)
			{
				_suppressRawKeys.Value = v;
			}
		}
	}
}
namespace Hotline.Bridge
{
	internal static class BridgeHost
	{
		internal static void Install()
		{
			HotlineBridge.RegisterPanel = delegate(string id, string title)
			{
				PanelRegistry.RegisterPanel(id, title);
			};
			HotlineBridge.RegisterAction = delegate(string panelId, string actionId, string label, Action run)
			{
				PanelRegistry.RegisterAction(panelId, actionId, label, run);
			};
			HotlineBridge.RegisterToggle = delegate(string panelId, string toggleId, string label, Func<bool> get, Action<bool> set)
			{
				PanelRegistry.RegisterToggle(panelId, toggleId, label, get, set);
			};
			HotlineBridge.RegisterText = delegate(string panelId, Func<string> provider)
			{
				PanelRegistry.RegisterText(panelId, provider);
			};
			HotlineBridge.BindPanelLog = delegate(string panelId)
			{
				PanelRegistry.BindPanelLog(panelId);
			};
			HotlineBridge.Log = delegate(string channel, int level, string message)
			{
				LogHub.Write(channel, level, message);
			};
			HotlineBridge.RegisterHotkey = delegate(string owner, string label, int key, Action run)
			{
				HotkeyRegistry.Register(owner, label, (KeyCode)key, run);
			};
		}
	}
	public static class HotlineBridge
	{
		public const int AbiVersion = 1;

		public static Action<string, string> RegisterPanel;

		public static Action<string, string, string, Action> RegisterAction;

		public static Action<string, string, string, Func<bool>, Action<bool>> RegisterToggle;

		public static Action<string, Func<string>> RegisterText;

		public static Action<string> BindPanelLog;

		public static Action<string, int, string> Log;

		public static Action<string, string, int, Action> RegisterHotkey;
	}
}