Decompiled source of Hotline v1.3.1

Hotline.dll

Decompiled 2 weeks 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 Hash.Api;
using Hotline;
using Hotline.Bridge;
using Hotline.Config;
using Hotline.Hotkeys;
using Hotline.Logging;
using Hotline.Panels;
using Hotline.UI;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
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.3.1", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-Hotline")]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DooDesch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © DooDesch")]
[assembly: AssemblyFileVersion("1.3.1.0")]
[assembly: AssemblyInformationalVersion("1.3.1+9c5778ab6bb5b0ea0b760827fef9d4335c464aa0")]
[assembly: AssemblyProduct("Hotline")]
[assembly: AssemblyTitle("Hotline")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.1.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 Hash.Api
{
	public static class HashCommands
	{
		private const string BridgeTypeName = "Hash.Bridge.HashBridge, Hash";

		private static readonly List<string[]> _pending = new List<string[]>();

		private static Action<string, string, string, string> _declare;

		private static bool _bound;

		public static bool Available
		{
			get
			{
				Bind();
				return _bound;
			}
		}

		private static string Owner
		{
			get
			{
				try
				{
					return Assembly.GetExecutingAssembly().GetName().Name ?? "";
				}
				catch
				{
					return "";
				}
			}
		}

		public static void Add(string word, string description, string example = null)
		{
			if (!string.IsNullOrEmpty(word))
			{
				Bind();
				if (_declare != null)
				{
					Safely(word, description, example);
					return;
				}
				_pending.Add(new string[3]
				{
					word,
					description ?? "",
					example ?? ""
				});
			}
		}

		private static void Safely(string word, string description, string example)
		{
			try
			{
				_declare(word, description ?? "", example ?? "", Owner);
			}
			catch
			{
			}
		}

		private static void Bind()
		{
			if (_bound)
			{
				return;
			}
			try
			{
				Type type = Type.GetType("Hash.Bridge.HashBridge, Hash", throwOnError: false);
				if (type == null)
				{
					return;
				}
				_declare = type.GetField("Declare", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) as Action<string, string, string, string>;
				if (_declare == null)
				{
					return;
				}
				_bound = true;
				foreach (string[] item in _pending)
				{
					Safely(item[0], item[1], item[2]);
				}
				_pending.Clear();
			}
			catch
			{
			}
		}
	}
}
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_00c9: 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)
			Instance = this;
			Log = ((MelonBase)this).LoggerInstance;
			HarmonyInst = ((MelonBase)this).HarmonyInstance;
			Preferences.Initialize();
			LogHub.Install();
			BridgeHost.Install();
			HashCommands.Add("hotline", "overlay: list, open, close, key", "hotline list");
			try
			{
				((MelonBase)this).HarmonyInstance.PatchAll();
			}
			catch (Exception ex)
			{
				Log.Warning("[Hotline] Harmony patch failed: " + ex.Message);
			}
			Instance log = Log;
			string[] obj = new string[5] { "Hotline v", null, null, null, null };
			MelonAssembly melonAssembly = ((MelonBase)this).MelonAssembly;
			obj[1] = ((melonAssembly == null) ? null : melonAssembly.Assembly?.GetName()?.Version?.ToString(3)) ?? "?";
			obj[2] = " - mod HUD & hotkey hub. Press ";
			obj[3] = ((object)Preferences.MasterKey/*cast due to .constrained prefix*/).ToString();
			obj[4] = " in-world to open the overlay ('hotline help' for commands).";
			log.Msg(string.Concat(obj));
		}

		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_0036: 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"))
					{
						Overlay.Show(show: true);
						foreach (string item in Interceptor.ModsForKey(Preferences.MasterKey))
						{
							WindowLayout.SetVisible(item, v: true);
						}
					}
					else
					{
						Overlay.Show(show: 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 "slider":
					SliderCmd(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] | slider <sliderId> [value] | 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 SliderCmd(string[] p)
		{
			if (p.Length <= 2)
			{
				Log("usage: hotline slider <sliderId> [value] (omit the value to read it).");
				return;
			}
			string text = p[2];
			SliderItem slider = PanelRegistry.GetSlider(text);
			double result;
			if (slider == null)
			{
				Log("no slider '" + text + "'");
			}
			else if (p.Length <= 3)
			{
				Log($"{text} = {PanelRegistry.GetSliderValue(text):0.###} {slider.Unit} (range {slider.Min:0.###}..{slider.Max:0.###}, step {slider.Step:0.###})".TrimEnd());
			}
			else if (!double.TryParse(p[3], NumberStyles.Float, CultureInfo.InvariantCulture, out result))
			{
				Log("not a number: " + p[3]);
			}
			else
			{
				PanelRegistry.SetSlider(text, result);
				Log($"{text} = {PanelRegistry.GetSliderValue(text):0.###} {slider.Unit}".TrimEnd());
			}
		}

		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 static class Overlay
	{
		private const string OverviewId = "overview";

		internal static bool IsOpen => Preferences.ShowHud;

		internal static void Show(bool show)
		{
			Preferences.SetShowHud(show);
			if (show)
			{
				WindowLayout.SetVisible("overview", v: true);
			}
		}

		internal static void ShowPanel(string panelId, bool show)
		{
			if (!string.IsNullOrEmpty(panelId))
			{
				if (show)
				{
					Show(show: true);
				}
				WindowLayout.SetVisible(panelId, show);
			}
		}

		internal static bool IsPanelVisible(string panelId)
		{
			if (string.IsNullOrEmpty(panelId))
			{
				return false;
			}
			if (Preferences.ShowHud)
			{
				return WindowLayout.IsVisible(panelId);
			}
			return false;
		}
	}
	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 const float SliderH = 14f;

		private const float KnobW = 10f;

		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 GUIStyle _img;

		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 string _sliderId;

		private static Rect _sliderTrack;

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

		private static float _nextText;

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

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

		private static Drag _drag = Drag.None;

		private static string _dragId;

		private static Vector2 _grab;

		private static Rect _startRect;

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

		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))
				{
					try
					{
						DrawWindow(text3, text3 == text2);
					}
					catch (Exception e)
					{
						ReportDrawFailure(text3, e);
					}
				}
			}
		}

		private static void ReportDrawFailure(string id, Exception e)
		{
			if (_drawFailed.Add(id))
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Error("panel '" + id + "' failed to draw and was skipped: " + e.Message);
				}
			}
		}

		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_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: 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);
			}
			for (int l = 0; l < panelModel.Sliders.Count; l++)
			{
				Slider(id, innerW, scroll, bodyRect, ref localY, panelModel.Sliders[l]);
			}
			for (int m = 0; m < panelModel.Images.Count; m++)
			{
				Image(id + ":" + m, innerW, scroll, bodyRect, ref localY);
			}
			if (panelModel.HasLog)
			{
				Label(innerW, scroll, bodyRect, ref localY, Text("log:" + id));
			}
		}

		private static void Slider(string id, float innerW, float scroll, Rect bodyRect, ref float localY, SliderItem s)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			if (s == null)
			{
				return;
			}
			double sliderValue = PanelRegistry.GetSliderValue(s.Id);
			string text = s.Label + "  <b>" + Format(sliderValue, s.Step) + "</b>" + (string.IsNullOrEmpty(s.Unit) ? "" : (" " + s.Unit));
			Label(innerW, scroll, bodyRect, ref localY, text);
			float num = Mathf.Max(60f, innerW);
			float num2 = localY - scroll;
			if (num2 + 14f > 0f && num2 < ((Rect)(ref bodyRect)).height)
			{
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(6f, num2, num, 14f);
				Rect rect = default(Rect);
				((Rect)(ref rect))..ctor(((Rect)(ref bodyRect)).x + 6f, ((Rect)(ref bodyRect)).y + num2, num, 14f);
				bool flag = _cursorFree && ((Rect)(ref rect)).Contains(_mouse);
				bool flag2 = _sliderId == s.Id;
				GUI.backgroundColor = new Color(0.16f, 0.17f, 0.24f, 0.98f);
				GUI.Box(val, GUIContent.none, _btn);
				float num3 = s.Fraction01();
				if (num3 > 0f)
				{
					GUI.backgroundColor = ((flag2 || flag) ? BtnOnHover : BtnOn);
					GUI.Box(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, Mathf.Max(2f, ((Rect)(ref val)).width * num3), ((Rect)(ref val)).height), GUIContent.none, _btn);
				}
				float num4 = Mathf.Clamp(((Rect)(ref val)).x + ((Rect)(ref val)).width * num3 - 5f, ((Rect)(ref val)).x, ((Rect)(ref val)).xMax - 10f);
				GUI.backgroundColor = ((flag2 || flag) ? new Color(0.95f, 0.96f, 1f, 1f) : new Color(0.78f, 0.81f, 0.92f, 1f));
				GUI.Box(new Rect(num4, ((Rect)(ref val)).y - 2f, 10f, ((Rect)(ref val)).height + 4f), GUIContent.none, _btn);
				GUI.backgroundColor = Color.white;
				_hits.Add(new Hit
				{
					Win = id,
					Rect = rect,
					Type = 4,
					Arg = s.Id
				});
			}
			localY += 18f;
		}

		private static string Format(double v, double step)
		{
			if (step >= 1.0 || step <= 0.0)
			{
				return v.ToString("0.##");
			}
			if (step >= 0.1)
			{
				return v.ToString("0.0");
			}
			if (step >= 0.01)
			{
				return v.ToString("0.00");
			}
			return v.ToString("0.000");
		}

		private static double ValueAt(SliderItem s, Rect track, float mouseX)
		{
			if (s == null || ((Rect)(ref track)).width <= 0f)
			{
				return 0.0;
			}
			float num = Mathf.Clamp01((mouseX - ((Rect)(ref track)).x) / ((Rect)(ref track)).width);
			return s.Min + (s.Max - s.Min) * (double)num;
		}

		private static void Image(string key, float innerW, float scroll, Rect bodyRect, ref float localY)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (_imgTex.TryGetValue(key, out var value) && !((Object)(object)value == (Object)null))
			{
				float num = Mathf.Min(innerW, (float)Mathf.Max(((Texture)value).width, 160));
				num = Mathf.Min(num, innerW);
				float num2 = localY - scroll;
				if (num2 + num > 0f && num2 < ((Rect)(ref bodyRect)).height)
				{
					_img.normal.background = value;
					GUI.Box(new Rect(6f, num2, num, num), GUIContent.none, _img);
				}
				localY += num + 4f;
			}
		}

		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_0079: 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)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: 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_0194: 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_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Cursor.lockState == 1)
			{
				_drag = Drag.None;
				_sliderId = null;
				return;
			}
			if (_sliderId != null)
			{
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(Input.mousePosition.x, (float)Screen.height - Input.mousePosition.y);
				if (Input.GetMouseButton(0))
				{
					SliderItem slider = PanelRegistry.GetSlider(_sliderId);
					if (slider != null)
					{
						PanelRegistry.SetSlider(_sliderId, ValueAt(slider, _sliderTrack, val.x));
					}
					return;
				}
				_sliderId = null;
			}
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(Input.mousePosition.x, (float)Screen.height - Input.mousePosition.y);
			float y = Input.mouseScrollDelta.y;
			if (Mathf.Abs(y) > 0.01f)
			{
				string text = TopWindowAt(val2, 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(val2, bodyOnly: false);
				if (text2 == null)
				{
					return;
				}
				BringToFront(text2);
				if (_closeRects.TryGetValue(text2, out var value) && ((Rect)(ref value)).Contains(val2))
				{
					WindowLayout.SetVisible(text2, v: false);
					return;
				}
				if (_gripRects.TryGetValue(text2, out var value2) && ((Rect)(ref value2)).Contains(val2))
				{
					_drag = Drag.Resize;
					_dragId = text2;
					_grab = val2;
					_startRect = _frameRects[text2];
					return;
				}
				if (_titleRects.TryGetValue(text2, out var value3) && ((Rect)(ref value3)).Contains(val2))
				{
					_drag = Drag.Move;
					_dragId = text2;
					Rect val3 = _frameRects[text2];
					_grab = val2 - new Vector2(((Rect)(ref val3)).x, ((Rect)(ref val3)).y);
					return;
				}
				for (int i = 0; i < _hits.Count; i++)
				{
					Hit hit = _hits[i];
					if (hit.Win != text2 || !((Rect)(ref hit.Rect)).Contains(val2))
					{
						continue;
					}
					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;
					case 4:
					{
						SliderItem slider2 = PanelRegistry.GetSlider(hit.Arg);
						if (slider2 != null)
						{
							_sliderId = hit.Arg;
							_sliderTrack = hit.Rect;
							PanelRegistry.SetSlider(hit.Arg, ValueAt(slider2, hit.Rect, val2.x));
						}
						break;
					}
					}
					break;
				}
			}
			else if (Input.GetMouseButton(0) && _drag != Drag.None)
			{
				if (_drag == Drag.Move)
				{
					WindowLayout.SetPos(_dragId, val2.x - _grab.x, val2.y - _grab.y);
				}
				else
				{
					WindowLayout.SetSize(_dragId, Mathf.Max(160f, ((Rect)(ref _startRect)).width + (val2.x - _grab.x)), Mathf.Max(70f, ((Rect)(ref _startRect)).height + (val2.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);
				}
				for (int j = 0; j < panelModel.Images.Count; j++)
				{
					RefreshImage(panelModel.Id + ":" + j, panelModel.Images[j]);
				}
			}
			_textCache["timeline"] = BuildTimelineText(220);
		}

		private static void RefreshImage(string key, Func<int[]> provider)
		{
			int[] d = null;
			try
			{
				d = provider?.Invoke();
			}
			catch
			{
			}
			int num = ImgHash(d);
			if (!_imgHash.TryGetValue(key, out var value) || value != num || !_imgTex.ContainsKey(key))
			{
				_imgHash[key] = num;
				if (_imgTex.TryGetValue(key, out var value2) && (Object)(object)value2 != (Object)null)
				{
					Object.Destroy((Object)(object)value2);
				}
				_imgTex[key] = BuildImageTexture(d);
			}
		}

		private static int ImgHash(int[] d)
		{
			if (d == null)
			{
				return 0;
			}
			int num = d.Length;
			int num2 = Mathf.Max(1, d.Length / 64);
			for (int i = 0; i < d.Length; i += num2)
			{
				num = num * 31 + d[i];
			}
			return num;
		}

		private static Texture2D BuildImageTexture(int[] d)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (d == null || d.Length < 2)
			{
				return null;
			}
			int num = d[0];
			int num2 = d[1];
			if (num <= 0 || num2 <= 0 || d.Length < 2 + num * num2)
			{
				return null;
			}
			Color32[] array = (Color32[])(object)new Color32[num * num2];
			for (int i = 0; i < num2; i++)
			{
				for (int j = 0; j < num; j++)
				{
					int num3 = d[2 + i * num + j];
					array[(num2 - 1 - i) * num + j] = new Color32((byte)(num3 >> 16), (byte)(num3 >> 8), (byte)num3, (byte)(num3 >> 24));
				}
			}
			Texture2D val = new Texture2D(num, num2, (TextureFormat)5, false)
			{
				filterMode = (FilterMode)0,
				wrapMode = (TextureWrapMode)1,
				hideFlags = (HideFlags)61
			};
			val.SetPixels32(Il2CppStructArray<Color32>.op_Implicit(array));
			val.Apply();
			return val;
		}

		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_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Expected O, but got Unknown
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Expected O, but got Unknown
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Expected O, but got Unknown
			//IL_020d: Expected O, but got Unknown
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Expected O, but got Unknown
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Expected O, but got Unknown
			//IL_0260: 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);
				_img = new GUIStyle
				{
					padding = new RectOffset(0, 0, 0, 0),
					margin = new RectOffset(0, 0, 0, 0),
					border = new RectOffset(0, 0, 0, 0)
				};
				_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 SliderItem
	{
		public string Id;

		public string Label;

		public string Unit;

		public double Min;

		public double Max;

		public double Step;

		public Func<double> Get;

		public Action<double> Set;

		public double Quantize(double v)
		{
			if (Max > Min)
			{
				if (v < Min)
				{
					v = Min;
				}
				else if (v > Max)
				{
					v = Max;
				}
			}
			if (Step > 0.0)
			{
				v = Min + Math.Round((v - Min) / Step) * Step;
			}
			return v;
		}

		public float Fraction01()
		{
			double num = Max - Min;
			if (num <= 0.0)
			{
				return 0f;
			}
			double num2 = 0.0;
			try
			{
				num2 = ((Get != null) ? Get() : Min);
			}
			catch
			{
			}
			double num3 = (num2 - Min) / num;
			return (float)((num3 < 0.0) ? 0.0 : ((num3 > 1.0) ? 1.0 : num3));
		}
	}
	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);

		public readonly List<SliderItem> Sliders = new List<SliderItem>(4);

		public readonly List<Func<int[]>> Images = new List<Func<int[]>>(1);
	}
	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);

		private static readonly Dictionary<string, SliderItem> _sliders = new Dictionary<string, SliderItem>(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 RegisterSlider(string panelId, string sliderId, string label, double min, double max, double step, string unit, Func<double> get, Action<double> set)
		{
			if (get != null && set != null && !string.IsNullOrEmpty(sliderId) && !(max <= min))
			{
				PanelModel orCreate = GetOrCreate(panelId, null);
				SliderItem sliderItem = new SliderItem
				{
					Id = sliderId,
					Label = (label ?? sliderId),
					Unit = (unit ?? ""),
					Min = min,
					Max = max,
					Step = ((step > 0.0) ? step : 0.0),
					Get = get,
					Set = set
				};
				orCreate.Sliders.RemoveAll((SliderItem s) => s.Id == sliderId);
				orCreate.Sliders.Add(sliderItem);
				_sliders[sliderId] = sliderItem;
			}
		}

		internal static void RegisterImage(string panelId, Func<int[]> provider)
		{
			if (provider != null)
			{
				GetOrCreate(panelId, null).Images.Add(provider);
			}
		}

		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;
		}

		internal static SliderItem GetSlider(string sliderId)
		{
			if (string.IsNullOrEmpty(sliderId))
			{
				return null;
			}
			_sliders.TryGetValue(sliderId, out var value);
			return value;
		}

		internal static bool SetSlider(string sliderId, double value)
		{
			SliderItem slider = GetSlider(sliderId);
			if (slider == null)
			{
				return false;
			}
			try
			{
				slider.Set?.Invoke(slider.Quantize(value));
			}
			catch (Exception ex)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("[hotline] slider '" + sliderId + "' threw: " + ex.Message);
				}
			}
			return true;
		}

		internal static double GetSliderValue(string sliderId)
		{
			SliderItem slider = GetSlider(sliderId);
			if (slider == null || slider.Get == null)
			{
				return 0.0;
			}
			try
			{
				return slider.Get();
			}
			catch
			{
				return 0.0;
			}
		}
	}
}
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.RegisterImage = delegate(string panelId, Func<int[]> provider)
			{
				PanelRegistry.RegisterImage(panelId, provider);
			};
			HotlineBridge.RegisterSlider = delegate(string panelId, string sliderId, string label, double min, double max, double step, string unit, Func<double> get, Action<double> set)
			{
				PanelRegistry.RegisterSlider(panelId, sliderId, label, min, max, step, unit, get, set);
			};
			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);
			};
			HotlineBridge.ShowOverlay = delegate(bool show)
			{
				Overlay.Show(show);
			};
			HotlineBridge.ShowPanel = delegate(string panelId, bool show)
			{
				Overlay.ShowPanel(panelId, show);
			};
			HotlineBridge.IsPanelVisible = (string panelId) => Overlay.IsPanelVisible(panelId);
		}
	}
	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;

		public static Action<string, Func<int[]>> RegisterImage;

		public static Action<string, string, string, double, double, double, string, Func<double>, Action<double>> RegisterSlider;

		public static Action<bool> ShowOverlay;

		public static Action<string, bool> ShowPanel;

		public static Func<string, bool> IsPanelVisible;
	}
}