Decompiled source of BoneMenuPlus v1.1.0

BoneMenuPlus.dll

Decompiled 2 hours ago
using System;
using System.Buffers.Binary;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BoneLib.BoneMenu;
using BoneLib.BoneMenu.UI;
using BoneMenuPlus;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.Marrow;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(BoneMenuPlusMod), "BoneMenu Plus", "1.1.0", "yoyobroyo/zakovr", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonAdditionalDependencies(new string[] { "BoneLib" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace BoneMenuPlus;

public sealed class BoneMenuPlusMod : MelonMod
{
	private const string Version = "1.1.0";

	private static BoneMenuPlusMod _instance;

	private MenuScreen _screen;

	private float _nextPageTry;

	private float _nextError;

	internal static Page OwnPage;

	public override void OnInitializeMelon()
	{
		_instance = this;
		Log.Init();
		Prefs.Load();
		Bank.Prepare();
		string text = Path.Combine(MelonEnvironment.UserDataDirectory, "BoneMenuPlus");
		try
		{
			Directory.CreateDirectory(text);
		}
		catch
		{
		}
		_screen = new MenuScreen(text);
		Prefs.Changed = delegate
		{
			Log.Info("Mod UI = " + Prefs.UseModUi + ", Thunderstore covers = " + Prefs.FetchCovers);
		};
		TryOwnPage();
		((MelonBase)this).LoggerInstance.Msg("BoneMenu Plus 1.1.0 loaded: MapMenuPlus look with BoneMenuOrganizer categories. Log: UserData/BoneMenuPlus/log.txt");
	}

	public override void OnUpdate()
	{
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		try
		{
			if (realtimeSinceStartup >= _nextPageTry)
			{
				_nextPageTry = realtimeSinceStartup + 2f;
				TryOwnPage();
			}
			_screen?.Tick(realtimeSinceStartup);
		}
		catch (Exception e)
		{
			if (realtimeSinceStartup >= _nextError)
			{
				_nextError = realtimeSinceStartup + 5f;
				Log.Error("Update failed", e);
			}
		}
	}

	private void TryOwnPage()
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (OwnPage == null && Page.Root != null)
			{
				OwnPage = Page.Root.CreatePage("BoneMenu Plus", Theme.Accent, 0, true);
				OwnPage.CreateBool("Mod UI", Theme.Accent, Prefs.UseModUi, (Action<bool>)delegate(bool value)
				{
					Prefs.SetUseModUi(value);
				});
				OwnPage.CreateBool("Thunderstore covers", Theme.Green, Prefs.FetchCovers, (Action<bool>)delegate(bool value)
				{
					Prefs.SetFetchCovers(value);
				});
				OwnPage.CreateFunction("Rescan mod pages", Theme.Rgb(255, 204, 87), (Action)delegate
				{
					Log.Info("Rescan requested from the BoneMenu page.");
				});
				Log.Info("BoneMenu page \"BoneMenu Plus\" added.");
			}
		}
		catch (Exception ex)
		{
			Log.Warn("Adding the BoneMenu page failed (retrying): " + ex.Message);
			OwnPage = null;
		}
	}

	public override void OnDeinitializeMelon()
	{
		try
		{
			_screen?.Shutdown();
		}
		catch
		{
		}
		_screen = null;
		OwnPage = null;
		_instance = null;
	}
}
internal sealed class Classification
{
	public string Category { get; set; } = "";

	public string Source { get; set; } = "";

	public string Description { get; set; } = "";
}
internal sealed class CustomCategory
{
	public string Id { get; set; } = "";

	public string Name { get; set; } = "";

	public string ColorName { get; set; } = "Cyan";
}
internal sealed class OrganizerSettings
{
	public int Mode { get; set; }

	public bool AiCategories { get; set; }

	public bool GenerateImages { get; set; }

	public int CardSizePercent { get; set; } = 100;

	public Dictionary<string, Classification> Categories { get; set; } = new Dictionary<string, Classification>(StringComparer.OrdinalIgnoreCase);

	public List<string> CustomOrder { get; set; } = new List<string>();

	public List<CustomCategory> CustomCategories { get; set; } = new List<CustomCategory>();

	public Dictionary<string, string> CustomAssignments { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
internal static class OrganizerLogic
{
	internal static readonly string[] Categories = new string[10] { "Performance", "Gameplay", "Player & Movement", "Weapons & Combat", "Spawning & Sandbox", "Multiplayer", "Visuals", "Audio", "Interface & Tools", "Other" };

	internal static string ModKey(string author, string modName)
	{
		return author + "|" + modName;
	}

	internal static string PlainName(string name)
	{
		return Regex.Replace(name ?? "", "<[^>]*>", "").Trim();
	}

	internal static string Normalize(string value)
	{
		string text = PlainName(value);
		string[] array = new string[5] { " settings", " options", " configuration", " config", " menu" };
		foreach (string text2 in array)
		{
			if (text.EndsWith(text2, StringComparison.OrdinalIgnoreCase))
			{
				text = text.Substring(0, text.Length - text2.Length).Trim();
			}
		}
		return new string(text.Where(char.IsLetterOrDigit).Select(char.ToLowerInvariant).ToArray());
	}

	internal static string DefaultCategory(string name)
	{
		string value = Normalize(name);
		if (Has(value, "performance", "fps", "optimizer", "optimization", "culling"))
		{
			return "Performance";
		}
		if (Has(value, "fusion", "multiplayer", "lobby", "network"))
		{
			return "Multiplayer";
		}
		if (Has(value, "spawn", "sandbox", "npc"))
		{
			return "Spawning & Sandbox";
		}
		if (Has(value, "noautoeject", "weapon", "ammo", "gun", "reload", "combat"))
		{
			return "Weapons & Combat";
		}
		if (Has(value, "flatplayer", "slidescale", "ragdollplayer", "movement", "locomotion", "avatar", "jump", "fly", "parkour"))
		{
			return "Player & Movement";
		}
		if (Has(value, "echolocation", "shader", "visual", "lighting", "graphics", "colorful"))
		{
			return "Visuals";
		}
		if (Has(value, "audio", "sound", "music", "voice"))
		{
			return "Audio";
		}
		if (Has(value, "boneai", "bonelib", "wrishub", "wristhub", "menu", "assistant", "thunderstore", "debug", "tool"))
		{
			return "Interface & Tools";
		}
		if (Has(value, "selfharm", "health", "damage", "difficulty", "gameplay"))
		{
			return "Gameplay";
		}
		return "Other";
	}

	private static bool Has(string value, params string[] fragments)
	{
		return fragments.Any(value.Contains);
	}
}
internal static class CategoryColors
{
	internal static readonly (string Name, Color Color)[] Palette = new(string, Color)[10]
	{
		("Cyan", new Color(0.35f, 0.85f, 1f)),
		("Blue", new Color(0.4f, 0.62f, 1f)),
		("Mint", new Color(0.45f, 0.95f, 0.78f)),
		("Green", new Color(0.55f, 0.9f, 0.4f)),
		("Yellow", new Color(1f, 0.9f, 0.4f)),
		("Orange", new Color(1f, 0.65f, 0.3f)),
		("Red", new Color(1f, 0.4f, 0.4f)),
		("Pink", new Color(1f, 0.55f, 0.8f)),
		("Purple", new Color(0.78f, 0.6f, 1f)),
		("White", new Color(0.95f, 0.95f, 0.95f))
	};

	internal static Color Get(string name)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		(string, Color)[] palette = Palette;
		for (int i = 0; i < palette.Length; i++)
		{
			(string, Color) tuple = palette[i];
			if (tuple.Item1 == name)
			{
				return tuple.Item2;
			}
		}
		return Palette[0].Color;
	}

	internal static Color ForCategory(string name)
	{
		//IL_027a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0226: 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_0265: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_0211: 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)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		switch (name)
		{
		case "Gameplay":
			return new Color(1f, 0.8f, 0.34f);
		case "Interface & Tools":
			return new Color(0.42f, 0.73f, 1f);
		case "Multiplayer":
			return new Color(0.35f, 0.94f, 0.73f);
		case "Performance":
			return new Color(0.58f, 0.95f, 0.38f);
		case "Player & Movement":
			return new Color(0.32f, 0.86f, 1f);
		case "Spawning & Sandbox":
			return new Color(0.82f, 0.58f, 1f);
		case "Visuals":
			return new Color(0.65f, 0.69f, 1f);
		case "Audio":
			return new Color(1f, 0.53f, 0.76f);
		case "Weapons & Combat":
			return new Color(1f, 0.63f, 0.32f);
		case "Other":
		case "Uncategorized":
		case "Unknown creator":
			return new Color(0.87f, 0.89f, 0.91f);
		default:
			return new Color(0.8f, 0.87f, 0.95f);
		}
	}
}
internal sealed class ModEntry
{
	internal int Id;

	internal string Name = "";

	internal string ModName = "";

	internal string Author = "Unknown creator";

	internal string Key = "";

	internal string ModKey = "";

	internal string Url = "";

	internal string Category = "Other";

	internal Color Color = Color.white;

	internal Page Target;
}
internal sealed class Catalog
{
	internal readonly List<ModEntry> Entries = new List<ModEntry>();

	internal readonly List<string> Categories = new List<string>();

	internal readonly Dictionary<string, List<ModEntry>> ByCategory = new Dictionary<string, List<ModEntry>>(StringComparer.OrdinalIgnoreCase);

	internal OrganizerSettings Settings = new OrganizerSettings();

	private HashSet<Page> _seen = new HashSet<Page>();

	internal int ModCount => Entries.Count;

	internal static string SettingsPath => Path.Combine(MelonEnvironment.UserDataDirectory, "BoneMenuOrganizer", "settings.json");

	internal void LoadSettings()
	{
		try
		{
			if (!File.Exists(SettingsPath))
			{
				return;
			}
			OrganizerSettings organizerSettings = JsonSerializer.Deserialize<OrganizerSettings>(File.ReadAllText(SettingsPath), new JsonSerializerOptions
			{
				PropertyNameCaseInsensitive = true
			});
			if (organizerSettings != null)
			{
				OrganizerSettings organizerSettings2 = organizerSettings;
				if (organizerSettings2.Categories == null)
				{
					Dictionary<string, Classification> dictionary = (organizerSettings2.Categories = new Dictionary<string, Classification>(StringComparer.OrdinalIgnoreCase));
				}
				organizerSettings2 = organizerSettings;
				if (organizerSettings2.CustomAssignments == null)
				{
					Dictionary<string, string> dictionary3 = (organizerSettings2.CustomAssignments = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase));
				}
				organizerSettings2 = organizerSettings;
				if (organizerSettings2.CustomCategories == null)
				{
					List<CustomCategory> list = (organizerSettings2.CustomCategories = new List<CustomCategory>());
				}
				Settings = organizerSettings;
				Log.Info("Read the BoneMenu Organizer categories (" + Settings.Categories.Count + " classified mods, " + Settings.CustomCategories.Count + " custom categories).");
			}
		}
		catch (Exception ex)
		{
			Log.Warn("Reading the organizer settings failed (default categories used): " + ex.Message);
			Settings = new OrganizerSettings();
		}
	}

	internal void Scan(Page root, Page ownPage)
	{
		//IL_022d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0232: Unknown result type (might be due to invalid IL or missing references)
		Entries.Clear();
		Categories.Clear();
		ByCategory.Clear();
		_seen.Clear();
		if (root == null)
		{
			return;
		}
		MelonMod[] melons;
		try
		{
			melons = MelonTypeBase<MelonMod>.RegisteredMelons.Where((MelonMod m) => !(m is BoneMenuPlusMod)).ToArray();
		}
		catch (Exception ex)
		{
			Log.Warn("Listing the registered mods failed: " + ex.Message);
			melons = Array.Empty<MelonMod>();
		}
		int num = 0;
		foreach (Element item in Walk(root))
		{
			PageLinkElement val = (PageLinkElement)(object)((item is PageLinkElement) ? item : null);
			if (val == null || val.LinkedPage == null)
			{
				continue;
			}
			Page val2 = Logical(val.LinkedPage);
			if (val2 != null && val2 != root && val2 != ownPage && _seen.Add(val2))
			{
				string text = OrganizerLogic.PlainName(((Element)val).ElementName);
				if (!IsOurName(text))
				{
					MelonMod val3 = Match(text, melons);
					string text2 = ((val3 != null && !string.IsNullOrWhiteSpace(((MelonBase)val3).Info.Author)) ? ((MelonBase)val3).Info.Author.Trim() : "Unknown creator");
					string text3 = ((val3 != null && !string.IsNullOrWhiteSpace(((MelonBase)val3).Info.Name)) ? ((MelonBase)val3).Info.Name.Trim() : text);
					ModEntry modEntry = new ModEntry();
					modEntry.Id = num++;
					modEntry.Name = text;
					modEntry.ModName = text3;
					modEntry.Author = text2;
					modEntry.ModKey = OrganizerLogic.ModKey(text2, text3);
					modEntry.Key = text2 + "|" + text3 + "|" + OrganizerLogic.Normalize(text);
					modEntry.Url = ((val3 != null) ? (((MelonBase)val3).Info.DownloadLink ?? "") : "");
					modEntry.Target = val2;
					ModEntry modEntry2 = modEntry;
					modEntry2.Category = CategoryFor(modEntry2);
					modEntry2.Color = CategoryColors.ForCategory(modEntry2.Category);
					Entries.Add(modEntry2);
				}
			}
		}
		BuildGroups();
	}

	private void BuildGroups()
	{
		foreach (ModEntry entry in Entries)
		{
			if (!ByCategory.TryGetValue(entry.Category, out var value))
			{
				value = new List<ModEntry>();
				ByCategory[entry.Category] = value;
			}
			value.Add(entry);
		}
		foreach (List<ModEntry> value2 in ByCategory.Values)
		{
			value2.Sort((ModEntry a, ModEntry b) => string.Compare(a.ModName, b.ModName, StringComparison.OrdinalIgnoreCase));
		}
		List<string> list = ByCategory.Keys.ToList();
		string[] categories = OrganizerLogic.Categories;
		foreach (string category in categories)
		{
			if (list.Contains<string>(category, StringComparer.OrdinalIgnoreCase) && !category.Equals("Other", StringComparison.OrdinalIgnoreCase))
			{
				Categories.Add(category);
				list.RemoveAll((string c) => c.Equals(category, StringComparison.OrdinalIgnoreCase));
			}
		}
		list.Sort(StringComparer.OrdinalIgnoreCase);
		foreach (string item in list)
		{
			if (!item.Equals("Other", StringComparison.OrdinalIgnoreCase))
			{
				Categories.Add(item);
			}
		}
		if (ByCategory.ContainsKey("Other"))
		{
			Categories.Add("Other");
		}
	}

	private string CategoryFor(ModEntry entry)
	{
		if (Settings.CustomAssignments != null && Settings.CustomAssignments.TryGetValue(entry.ModKey, out var id) && !string.IsNullOrEmpty(id))
		{
			CustomCategory customCategory = Settings.CustomCategories?.FirstOrDefault((CustomCategory c) => c.Id == id);
			if (customCategory != null && !string.IsNullOrWhiteSpace(customCategory.Name))
			{
				return customCategory.Name;
			}
		}
		if (Settings.Categories != null)
		{
			if (Settings.Categories.TryGetValue(entry.Key, out var value) && value != null && OrganizerLogic.Categories.Contains(value.Category))
			{
				return value.Category;
			}
			foreach (KeyValuePair<string, Classification> category in Settings.Categories)
			{
				if (category.Value != null && OrganizerLogic.Categories.Contains(category.Value.Category) && category.Key.StartsWith(entry.ModKey + "|", StringComparison.OrdinalIgnoreCase))
				{
					return category.Value.Category;
				}
			}
		}
		return OrganizerLogic.DefaultCategory(entry.ModName);
	}

	internal List<ModEntry> Shown(string category)
	{
		if (string.IsNullOrEmpty(category) || category == "All")
		{
			return Entries;
		}
		if (ByCategory.TryGetValue(category, out var value))
		{
			return value;
		}
		return new List<ModEntry>();
	}

	internal int Count(string category)
	{
		return Shown(category).Count;
	}

	private static bool IsOurName(string name)
	{
		return name.Equals("BoneMenu Plus", StringComparison.OrdinalIgnoreCase);
	}

	private static MelonMod Match(string plain, MelonMod[] melons)
	{
		string text = OrganizerLogic.Normalize(plain);
		MelonMod result = null;
		int num = 0;
		foreach (MelonMod val in melons)
		{
			if (val == null)
			{
				continue;
			}
			string text2 = OrganizerLogic.Normalize(((MelonBase)val).Info.Name);
			if (text2.Length < 3 || text.Length < 3)
			{
				continue;
			}
			bool flag = text == text2;
			bool flag2 = text.StartsWith(text2) || text2.StartsWith(text);
			if (flag || flag2)
			{
				int num2 = Math.Min(text.Length, text2.Length) + (flag ? 1000 : 0);
				if (num2 > num)
				{
					num = num2;
					result = val;
				}
			}
		}
		return result;
	}

	internal static Page Logical(Page page)
	{
		HashSet<Page> hashSet = new HashSet<Page>();
		while (page != null && page.IsIndexedChild && page.Parent != null && hashSet.Add(page))
		{
			page = page.Parent;
		}
		return page;
	}

	internal static IEnumerable<Element> Walk(Page page)
	{
		HashSet<Page> visited = new HashSet<Page>();
		Queue<Page> pending = new Queue<Page>();
		pending.Enqueue(page);
		while (pending.Count > 0)
		{
			Page current = pending.Dequeue();
			if (current == null || !visited.Add(current))
			{
				continue;
			}
			foreach (Element element in current.Elements)
			{
				yield return element;
			}
			foreach (Page indexPage in current.IndexPages)
			{
				pending.Enqueue(indexPage);
			}
		}
	}

	internal static List<Element> Flatten(Page page)
	{
		List<Element> list = new List<Element>();
		if (page == null)
		{
			return list;
		}
		HashSet<Element> hashSet = new HashSet<Element>();
		foreach (Element element in page.Elements)
		{
			if (element != null && hashSet.Add(element))
			{
				list.Add(element);
			}
		}
		foreach (Page indexPage in page.IndexPages)
		{
			if (indexPage == null)
			{
				continue;
			}
			foreach (Element element2 in indexPage.Elements)
			{
				if (element2 != null && hashSet.Add(element2))
				{
					list.Add(element2);
				}
			}
		}
		return list;
	}
}
internal sealed class Covers : IDisposable
{
	private sealed class Job
	{
		internal string Key = "";

		internal string Url = "";

		internal string Name = "";

		internal string Mod = "";
	}

	private sealed class IndexEntry
	{
		internal string Namespace = "";

		internal string Name = "";

		internal string Icon = "";
	}

	private const int MaxIconBytes = 8388608;

	private const int MaxApiBytes = 4194304;

	private const int MaxIndexBytes = 33554432;

	private const string IndexUrl = "https://thunderstore.io/c/bonelab/api/v1/package/";

	private static readonly HttpClient Http = MakeClient();

	private readonly string _directory;

	private readonly string _indexCachePath;

	private readonly BlockingCollection<Job> _jobs = new BlockingCollection<Job>();

	private readonly ConcurrentDictionary<string, byte> _queued = new ConcurrentDictionary<string, byte>(StringComparer.OrdinalIgnoreCase);

	private readonly Dictionary<string, Texture2D> _textures = new Dictionary<string, Texture2D>(StringComparer.OrdinalIgnoreCase);

	private readonly HashSet<string> _bad = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private readonly CancellationTokenSource _cancel = new CancellationTokenSource();

	private readonly Thread _worker;

	private readonly object _indexLock = new object();

	private Dictionary<string, IndexEntry> _index;

	private bool _indexTried;

	private int _downloaded;

	private int _failed;

	private float _nextLoad;

	internal int Downloaded => _downloaded;

	internal int Failed => _failed;

	internal int Pending => _jobs.Count;

	internal Covers(string dataDirectory)
	{
		_directory = Path.Combine(dataDirectory, "covers");
		_indexCachePath = Path.Combine(dataDirectory, "thunderstore-index.json");
		try
		{
			Directory.CreateDirectory(_directory);
		}
		catch
		{
		}
		_worker = new Thread(Work)
		{
			IsBackground = true,
			Name = "BoneMenuPlus covers"
		};
		_worker.Start();
	}

	private static HttpClient MakeClient()
	{
		HttpClient httpClient = new HttpClient(new HttpClientHandler
		{
			AllowAutoRedirect = true,
			MaxAutomaticRedirections = 5
		})
		{
			Timeout = TimeSpan.FromSeconds(30.0)
		};
		try
		{
			httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "BoneMenuPlus/1.1 (BONELAB BoneMenu mod)");
			httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/json,image/png,image/jpeg,*/*");
		}
		catch
		{
		}
		return httpClient;
	}

	internal Texture2D Get(ModEntry entry, float now)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Expected O, but got Unknown
		if (entry == null)
		{
			return null;
		}
		string text = FileKey(entry);
		if (_textures.TryGetValue(text, out var value))
		{
			if ((Object)value != (Object)null)
			{
				return value;
			}
			_textures.Remove(text);
		}
		if (_bad.Contains(text))
		{
			return null;
		}
		string path = PathFor(text);
		if (File.Exists(path))
		{
			if (now < _nextLoad)
			{
				return null;
			}
			_nextLoad = now + 0.05f;
			Texture2D val = Load(text, path);
			if ((Object)val != (Object)null)
			{
				return val;
			}
		}
		if (Prefs.FetchCovers)
		{
			Request(new Job
			{
				Key = text,
				Url = (entry.Url ?? ""),
				Name = (entry.Name ?? ""),
				Mod = (entry.ModName ?? "")
			});
		}
		return null;
	}

	private void Request(Job job)
	{
		if (!_queued.TryAdd(job.Key, 0))
		{
			return;
		}
		try
		{
			_jobs.Add(job, _cancel.Token);
		}
		catch (Exception)
		{
		}
	}

	private Texture2D Load(string key, string path)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Expected O, but got Unknown
		try
		{
			byte[] array = File.ReadAllBytes(path);
			if (!IsImage(array))
			{
				Drop(key, path);
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, new Il2CppStructArray<byte>(array), true))
			{
				Object.Destroy((Object)val);
				Drop(key, path);
				return null;
			}
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)2;
			((Texture)val).anisoLevel = 3;
			((Object)val).hideFlags = (HideFlags)32;
			((Object)val).name = "BMP_cover_" + key;
			_textures[key] = val;
			return val;
		}
		catch (Exception ex)
		{
			Log.Warn("Reading a cover failed: " + ex.Message);
			Drop(key, path);
			return null;
		}
	}

	private void Drop(string key, string path)
	{
		_bad.Add(key);
		try
		{
			File.Delete(path);
		}
		catch
		{
		}
	}

	private void Work()
	{
		try
		{
			foreach (Job item in _jobs.GetConsumingEnumerable(_cancel.Token))
			{
				if (_cancel.IsCancellationRequested)
				{
					break;
				}
				try
				{
					string text = PathFor(item.Key);
					if (!File.Exists(text))
					{
						byte[] array = FetchIcon(item.Url);
						if (array == null)
						{
							array = FetchByName(item.Name);
						}
						if (array == null && !string.Equals(item.Mod, item.Name, StringComparison.OrdinalIgnoreCase))
						{
							array = FetchByName(item.Mod);
						}
						if (array == null)
						{
							_failed++;
							continue;
						}
						File.WriteAllBytes(text + ".tmp", array);
						File.Move(text + ".tmp", text, overwrite: true);
						_downloaded++;
					}
				}
				catch (Exception ex)
				{
					_failed++;
					Log.Warn("Fetching a Thunderstore cover failed: " + ex.Message);
				}
			}
		}
		catch (OperationCanceledException)
		{
		}
		catch (ObjectDisposedException)
		{
		}
	}

	private static byte[] FetchIcon(string source)
	{
		if (string.IsNullOrWhiteSpace(source))
		{
			return null;
		}
		if (!TryIdentity(source, out var packageNamespace, out var packageName))
		{
			if (TrustedIcon(source, out var uri))
			{
				return DownloadIcon(uri.AbsoluteUri);
			}
			return null;
		}
		byte[] array = ApiIcon(packageNamespace, packageName);
		if (array != null)
		{
			return array;
		}
		return DownloadIcon("https://thunderstore.io/c/bonelab/p/" + Uri.EscapeDataString(packageNamespace) + "/" + Uri.EscapeDataString(packageName) + "/");
	}

	private static byte[] ApiIcon(string packageNamespace, string packageName)
	{
		byte[] bounded = GetBounded("https://thunderstore.io/api/experimental/package/" + Uri.EscapeDataString(packageNamespace) + "/" + Uri.EscapeDataString(packageName) + "/", 4194304);
		if (bounded == null)
		{
			return null;
		}
		try
		{
			using JsonDocument jsonDocument = JsonDocument.Parse(bounded);
			JsonElement rootElement = jsonDocument.RootElement;
			if (!rootElement.TryGetProperty("namespace", out var value) || !string.Equals(value.GetString(), packageNamespace, StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			if (!rootElement.TryGetProperty("name", out var value2) || !string.Equals(value2.GetString(), packageName, StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			string text = ReadIcon(rootElement);
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			return DownloadIcon(text);
		}
		catch (Exception)
		{
			return null;
		}
	}

	private static string ReadIcon(JsonElement package)
	{
		if (package.TryGetProperty("latest", out var value) && value.ValueKind == JsonValueKind.Object && value.TryGetProperty("icon", out var value2) && value2.ValueKind == JsonValueKind.String)
		{
			string text = value2.GetString();
			if (!string.IsNullOrWhiteSpace(text))
			{
				return text;
			}
		}
		if (package.TryGetProperty("versions", out var value3) && value3.ValueKind == JsonValueKind.Array)
		{
			foreach (JsonElement item in value3.EnumerateArray())
			{
				if (item.ValueKind == JsonValueKind.Object && item.TryGetProperty("icon", out var value4) && value4.ValueKind == JsonValueKind.String)
				{
					string text2 = value4.GetString();
					if (!string.IsNullOrWhiteSpace(text2))
					{
						return text2;
					}
				}
			}
		}
		return "";
	}

	private byte[] FetchByName(string name)
	{
		if (string.IsNullOrWhiteSpace(name))
		{
			return null;
		}
		Dictionary<string, IndexEntry> dictionary = CommunityIndex();
		if (dictionary == null || dictionary.Count == 0)
		{
			return null;
		}
		if (!dictionary.TryGetValue(Tiny(name), out var value) || value == null)
		{
			string text = OrganizerLogic.Normalize(name);
			if (string.IsNullOrEmpty(text) || !dictionary.TryGetValue(text, out value) || value == null)
			{
				return null;
			}
		}
		if (!string.IsNullOrEmpty(value.Icon))
		{
			byte[] array = DownloadIcon(value.Icon);
			if (array != null)
			{
				return array;
			}
		}
		if (!string.IsNullOrEmpty(value.Namespace) && !string.IsNullOrEmpty(value.Name))
		{
			return ApiIcon(value.Namespace, value.Name);
		}
		return null;
	}

	private Dictionary<string, IndexEntry> CommunityIndex()
	{
		lock (_indexLock)
		{
			if (_indexTried)
			{
				return _index;
			}
			_indexTried = true;
			try
			{
				byte[] array = CachedIndex();
				if (array == null)
				{
					Log.Warn("The Thunderstore package list could not be read.");
					return null;
				}
				Dictionary<string, IndexEntry> dictionary = new Dictionary<string, IndexEntry>(StringComparer.OrdinalIgnoreCase);
				using JsonDocument jsonDocument = JsonDocument.Parse(array);
				foreach (JsonElement item in jsonDocument.RootElement.EnumerateArray())
				{
					if (!item.TryGetProperty("name", out var value) || value.ValueKind != JsonValueKind.String)
					{
						continue;
					}
					string text = value.GetString();
					if (string.IsNullOrWhiteSpace(text))
					{
						continue;
					}
					IndexEntry indexEntry = new IndexEntry
					{
						Name = text,
						Icon = ReadIcon(item)
					};
					if (item.TryGetProperty("owner", out var value2) && value2.ValueKind == JsonValueKind.String)
					{
						indexEntry.Namespace = value2.GetString() ?? "";
					}
					if (string.IsNullOrEmpty(indexEntry.Namespace) && item.TryGetProperty("full_name", out var value3) && value3.ValueKind == JsonValueKind.String)
					{
						string text2 = value3.GetString() ?? "";
						int num = text2.LastIndexOf('-');
						if (num > 0)
						{
							indexEntry.Namespace = text2.Substring(0, num);
							if (string.IsNullOrEmpty(indexEntry.Icon))
							{
								indexEntry.Name = text2.Substring(num + 1);
							}
						}
					}
					string text3 = Tiny(text);
					if (text3.Length > 2 && !dictionary.ContainsKey(text3))
					{
						dictionary[text3] = indexEntry;
					}
					if (item.TryGetProperty("full_name", out var value4) && value4.ValueKind == JsonValueKind.String)
					{
						string text4 = Tiny(value4.GetString());
						if (text4.Length > 2 && !dictionary.ContainsKey(text4))
						{
							dictionary[text4] = indexEntry;
						}
					}
				}
				_index = dictionary;
				Log.Info("Thunderstore covers: indexed " + dictionary.Count + " package names.");
				return dictionary;
			}
			catch (Exception ex)
			{
				Log.Warn("Reading the Thunderstore package list failed: " + ex.Message);
				return null;
			}
		}
	}

	private byte[] CachedIndex()
	{
		try
		{
			if (File.Exists(_indexCachePath))
			{
				FileInfo fileInfo = new FileInfo(_indexCachePath);
				if ((DateTime.UtcNow - fileInfo.LastWriteTimeUtc).TotalHours < 24.0)
				{
					byte[] array = File.ReadAllBytes(_indexCachePath);
					if (array.Length > 1024)
					{
						return array;
					}
				}
			}
		}
		catch
		{
		}
		byte[] bounded = GetBounded("https://thunderstore.io/c/bonelab/api/v1/package/", 33554432);
		if (bounded == null)
		{
			return null;
		}
		try
		{
			File.WriteAllBytes(_indexCachePath, bounded);
		}
		catch
		{
		}
		return bounded;
	}

	private static string Tiny(string value)
	{
		if (string.IsNullOrEmpty(value))
		{
			return "";
		}
		StringBuilder stringBuilder = new StringBuilder(value.Length);
		foreach (char c in value)
		{
			if (char.IsLetterOrDigit(c))
			{
				stringBuilder.Append(char.ToLowerInvariant(c));
			}
		}
		return stringBuilder.ToString();
	}

	private static byte[] DownloadIcon(string source)
	{
		if (!TrustedIcon(source, out var uri))
		{
			return null;
		}
		byte[] bounded = GetBounded(uri.AbsoluteUri, 8388608);
		if (bounded == null || !IsImage(bounded))
		{
			return null;
		}
		return bounded;
	}

	private static bool TryIdentity(string source, out string packageNamespace, out string packageName)
	{
		packageNamespace = (packageName = "");
		if (!Uri.TryCreate(source, UriKind.Absolute, out Uri result) || result.Scheme != Uri.UriSchemeHttps || !result.IsDefaultPort || result.UserInfo.Length != 0)
		{
			return false;
		}
		if (!result.Host.EndsWith("thunderstore.io", StringComparison.OrdinalIgnoreCase))
		{
			return false;
		}
		string[] array = result.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
		int num = ((array.Length >= 3 && (array[0].Equals("package", StringComparison.OrdinalIgnoreCase) || array[0].Equals("p", StringComparison.OrdinalIgnoreCase))) ? 1 : ((array.Length >= 5 && array[0].Equals("c", StringComparison.OrdinalIgnoreCase) && (array[2].Equals("p", StringComparison.OrdinalIgnoreCase) || array[2].Equals("package", StringComparison.OrdinalIgnoreCase))) ? 3 : (-1)));
		if (num < 0)
		{
			return false;
		}
		packageNamespace = Uri.UnescapeDataString(array[num]);
		packageName = Uri.UnescapeDataString(array[num + 1]);
		if (Safe(packageNamespace))
		{
			return Safe(packageName);
		}
		return false;
	}

	private static bool Safe(string value)
	{
		if (!string.IsNullOrEmpty(value) && value.Length <= 80)
		{
			return value.All((char c) => char.IsLetterOrDigit(c) || c == '_' || c == '-' || c == '.');
		}
		return false;
	}

	private static bool TrustedIcon(string source, out Uri uri)
	{
		uri = null;
		if (!Uri.TryCreate(source, UriKind.Absolute, out Uri result) || result.Scheme != Uri.UriSchemeHttps || result.UserInfo.Length != 0)
		{
			return false;
		}
		if (!result.Host.EndsWith("thunderstore.io", StringComparison.OrdinalIgnoreCase))
		{
			return false;
		}
		uri = result;
		return true;
	}

	private static byte[] GetBounded(string url, int maxBytes)
	{
		try
		{
			using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
			using HttpResponseMessage httpResponseMessage = Http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).GetAwaiter().GetResult();
			if (!httpResponseMessage.IsSuccessStatusCode || httpResponseMessage.Content.Headers.ContentLength > maxBytes)
			{
				return null;
			}
			Uri uri = ((httpResponseMessage.RequestMessage != null) ? httpResponseMessage.RequestMessage.RequestUri : null);
			if (uri != null && !uri.Host.EndsWith("thunderstore.io", StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			byte[] result = httpResponseMessage.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
			if (result == null || result.Length == 0 || result.Length > maxBytes)
			{
				return null;
			}
			return result;
		}
		catch (Exception)
		{
			return null;
		}
	}

	private static bool IsImage(byte[] bytes)
	{
		if (bytes == null || bytes.Length < 24)
		{
			return false;
		}
		if (bytes[0] == 137 && bytes[1] == 80 && bytes[2] == 78 && bytes[3] == 71 && bytes[4] == 13 && bytes[5] == 10 && bytes[6] == 26 && bytes[7] == 10)
		{
			if (bytes[12] != 73 || bytes[13] != 72 || bytes[14] != 68 || bytes[15] != 82)
			{
				return false;
			}
			int num = BinaryPrimitives.ReadInt32BigEndian(bytes.AsSpan(16, 4));
			int num2 = BinaryPrimitives.ReadInt32BigEndian(bytes.AsSpan(20, 4));
			if (num > 0 && num <= 4096 && num2 > 0)
			{
				return num2 <= 4096;
			}
			return false;
		}
		if (bytes[0] == byte.MaxValue && bytes[1] == 216)
		{
			return bytes[2] == byte.MaxValue;
		}
		return false;
	}

	private static string FileKey(ModEntry entry)
	{
		return entry.Key.ToUpperInvariant();
	}

	private string PathFor(string key)
	{
		return Path.Combine(_directory, Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(key))).ToLowerInvariant() + ".png");
	}

	public void Dispose()
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Expected O, but got Unknown
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Expected O, but got Unknown
		try
		{
			_cancel.Cancel();
			_jobs.CompleteAdding();
		}
		catch
		{
		}
		foreach (Texture2D value in _textures.Values)
		{
			try
			{
				if ((Object)value != (Object)null)
				{
					Object.Destroy((Object)value);
				}
			}
			catch
			{
			}
		}
		_textures.Clear();
	}
}
internal sealed class CursorArea
{
	private const float RefindEvery = 3f;

	private readonly List<LaserCursor> _cursors = new List<LaserCursor>();

	private GameObject _go;

	private float _nextFind;

	private Vector3 _size;

	private bool _attached;

	private int _logs;

	internal void Show(float now, Transform frame, Vector2 centre, Vector2 size, float depth)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Expected O, but got Unknown
		//IL_0080: 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_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: 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)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: 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)
		if ((Object)frame == (Object)null)
		{
			return;
		}
		try
		{
			if ((Object)_go == (Object)null)
			{
				_go = new GameObject("BMP_CursorArea");
			}
			Vector3 val = frame.TransformPoint(new Vector3(1f, 0f, 0f)) - frame.TransformPoint(Vector3.zero);
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (!(magnitude < 1E-07f))
			{
				Transform transform = _go.transform;
				transform.position = frame.TransformPoint(new Vector3(centre.x, centre.y, 0f));
				transform.rotation = frame.rotation;
				Vector3 val2 = default(Vector3);
				((Vector3)(ref val2))..ctor(size.x * magnitude, size.y * magnitude, depth * magnitude);
				Vector3 val3 = val2 - _size;
				if (((Vector3)(ref val3)).sqrMagnitude > 1E-06f || !_attached || now >= _nextFind)
				{
					_size = val2;
					_nextFind = now + 3f;
					Attach();
				}
			}
		}
		catch (Exception e)
		{
			if (_logs++ < 5)
			{
				Log.Error("Cursor area update failed", e);
			}
		}
	}

	internal void Hide()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Expected O, but got Unknown
		if (!_attached)
		{
			return;
		}
		_attached = false;
		foreach (LaserCursor cursor in _cursors)
		{
			try
			{
				if ((Object)cursor != (Object)null)
				{
					SetRegions(cursor, add: false);
				}
			}
			catch
			{
			}
		}
		_cursors.Clear();
	}

	internal void Reset()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		//IL_0036: 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_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Expected O, but got Unknown
		Hide();
		try
		{
			if ((Object)_go != (Object)null)
			{
				Object.Destroy((Object)_go);
			}
		}
		catch
		{
		}
		_go = null;
		_size = Vector3.zero;
	}

	private void Attach()
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Expected O, but got Unknown
		_cursors.Clear();
		foreach (LaserCursor item in Object.FindObjectsOfType<LaserCursor>(true))
		{
			if ((Object)item != (Object)null)
			{
				_cursors.Add(item);
			}
		}
		int num = 0;
		foreach (LaserCursor cursor in _cursors)
		{
			try
			{
				if (SetRegions(cursor, add: true))
				{
					num++;
				}
			}
			catch (Exception ex)
			{
				if (_logs++ < 5)
				{
					Log.Warn("Adding the cursor area failed: " + ex.Message);
				}
			}
		}
		if (!_attached && _logs++ < 5)
		{
			Log.Info("Laser cursor area added to " + num + " of " + _cursors.Count + " laser cursor(s).");
		}
		_attached = true;
	}

	private bool SetRegions(LaserCursor cursor, bool add)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Expected O, but got Unknown
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Expected O, but got Unknown
		//IL_0054: 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)
		//IL_00af: 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)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Expected O, but got Unknown
		Il2CppReferenceArray<CursorRegion> regions = cursor.regions;
		List<CursorRegion> list = new List<CursorRegion>();
		int num = 0;
		if (regions != null)
		{
			for (int i = 0; i < ((Il2CppArrayBase<CursorRegion>)(object)regions).Length; i++)
			{
				CursorRegion val = ((Il2CppArrayBase<CursorRegion>)(object)regions)[i];
				Transform val2 = null;
				try
				{
					val2 = val.center;
				}
				catch
				{
				}
				if ((Object)val2 != (Object)null && (Object)_go != (Object)null && ((Object)val2).GetInstanceID() == ((Object)_go.transform).GetInstanceID())
				{
					num++;
				}
				else
				{
					list.Add(val);
				}
			}
		}
		if (!add && num == 0)
		{
			return false;
		}
		if (add && (Object)_go != (Object)null)
		{
			list.Add(new CursorRegion
			{
				bounds = new Bounds(Vector3.zero, _size),
				center = _go.transform
			});
		}
		cursor.regions = new Il2CppReferenceArray<CursorRegion>(list.ToArray());
		return add;
	}
}
internal struct HudRect
{
	internal float X;

	internal float Y;

	internal float W;

	internal float H;

	internal float Left => X - W / 2f;

	internal float Right => X + W / 2f;

	internal float Top => Y + H / 2f;

	internal float Bottom => Y - H / 2f;

	internal HudRect(float x, float y, float w, float h)
	{
		X = x;
		Y = y;
		W = w;
		H = h;
	}
}
internal struct Rgba
{
	internal float R;

	internal float G;

	internal float B;

	internal float A;

	internal static readonly Rgba White = new Rgba(1f, 1f, 1f);

	internal Rgba(float r, float g, float b, float a = 1f)
	{
		R = r;
		G = g;
		B = b;
		A = a;
	}

	internal static Rgba Bytes(int r, int g, int b, int a = 255)
	{
		return new Rgba((float)r / 255f, (float)g / 255f, (float)b / 255f, (float)a / 255f);
	}

	internal static Rgba Lerp(Rgba a, Rgba b, float t)
	{
		return new Rgba(a.R + (b.R - a.R) * t, a.G + (b.G - a.G) * t, a.B + (b.B - a.B) * t, a.A + (b.A - a.A) * t);
	}
}
internal sealed class Pic
{
	internal readonly int W;

	internal readonly int H;

	internal readonly byte[] Px;

	internal Pic(int w, int h)
	{
		W = w;
		H = h;
		Px = new byte[w * h * 4];
	}
}
internal static class Shapes
{
	internal delegate bool Inside(float x, float y);

	private static readonly float[] StarPts = MakeStar();

	internal static readonly string[] IconNames = new string[25]
	{
		"person", "grid", "star", "star_outline", "clock", "list", "back", "gear", "search", "chevron_up",
		"chevron_down", "check", "close", "eye", "play", "download", "dice", "map", "cube", "spark",
		"diamond", "heart", "user", "chevron_left", "chevron_right"
	};

	internal static Pic RoundRect(int w, int h, float rTL, float rTR, float rBR, float rBL, Rgba left, Rgba right)
	{
		Pic pic = new Pic(w, h);
		float num = (float)w / 2f;
		float num2 = (float)h / 2f;
		for (int i = 0; i < h; i++)
		{
			for (int j = 0; j < w; j++)
			{
				float num3 = (float)j + 0.5f - num;
				float num4 = (float)i + 0.5f - num2;
				float r = ((num3 < 0f) ? ((num4 > 0f) ? rTL : rBL) : ((num4 > 0f) ? rTR : rBR));
				float num5 = BoxSdf(num3, num4, num, num2, r);
				float cov = Clamp01(0.5f - num5);
				float t = ((w > 1) ? (((float)j + 0.5f) / (float)w) : 0f);
				Put(pic, j, i, Rgba.Lerp(left, right, t), cov);
			}
		}
		return pic;
	}

	internal static Pic RoundRect(int w, int h, float r, Rgba c)
	{
		return RoundRect(w, h, r, r, r, r, c, c);
	}

	internal static Pic RoundRectOutline(int w, int h, float r, float thickness, Rgba c)
	{
		Pic pic = new Pic(w, h);
		float num = (float)w / 2f;
		float num2 = (float)h / 2f;
		for (int i = 0; i < h; i++)
		{
			for (int j = 0; j < w; j++)
			{
				float px = (float)j + 0.5f - num;
				float py = (float)i + 0.5f - num2;
				float value = BoxSdf(px, py, num - thickness / 2f, num2 - thickness / 2f, Math.Max(0f, r - thickness / 2f));
				float cov = Clamp01(0.5f - (Math.Abs(value) - thickness / 2f));
				Put(pic, j, i, c, cov);
			}
		}
		return pic;
	}

	private static float BoxSdf(float px, float py, float hw, float hh, float r)
	{
		r = Math.Min(r, Math.Min(hw, hh));
		float val = Math.Abs(px) - (hw - r);
		float num = Math.Abs(py) - (hh - r);
		float num2 = Math.Max(val, 0f);
		float num3 = Math.Max(num, 0f);
		return (float)Math.Sqrt(num2 * num2 + num3 * num3) + Math.Min(Math.Max(val, num), 0f) - r;
	}

	internal static Pic Circle(int size, Rgba c)
	{
		Pic pic = new Pic(size, size);
		float num = (float)size / 2f;
		for (int i = 0; i < size; i++)
		{
			for (int j = 0; j < size; j++)
			{
				float num2 = (float)j + 0.5f - num;
				float num3 = (float)i + 0.5f - num;
				float cov = Clamp01(0.5f - ((float)Math.Sqrt(num2 * num2 + num3 * num3) - num + 0.5f));
				Put(pic, j, i, c, cov);
			}
		}
		return pic;
	}

	internal static Pic Icon(int size, Inside inside, Rgba c)
	{
		Pic pic = new Pic(size, size);
		for (int i = 0; i < size; i++)
		{
			for (int j = 0; j < size; j++)
			{
				int num = 0;
				for (int k = 0; k < 4; k++)
				{
					for (int l = 0; l < 4; l++)
					{
						float x = ((float)j + ((float)l + 0.5f) / 4f) / (float)size * 2f - 1f;
						float y = ((float)i + ((float)k + 0.5f) / 4f) / (float)size * 2f - 1f;
						if (inside(x, y))
						{
							num++;
						}
					}
				}
				Put(pic, j, i, c, (float)num / 16f);
			}
		}
		return pic;
	}

	internal static bool Seg(float x, float y, float ax, float ay, float bx, float by, float r)
	{
		float num = x - ax;
		float num2 = y - ay;
		float num3 = bx - ax;
		float num4 = by - ay;
		float num5 = Clamp01((num * num3 + num2 * num4) / (num3 * num3 + num4 * num4));
		float num6 = num - num3 * num5;
		float num7 = num2 - num4 * num5;
		return num6 * num6 + num7 * num7 <= r * r;
	}

	internal static bool Disc(float x, float y, float cx, float cy, float r)
	{
		float num = x - cx;
		float num2 = y - cy;
		return num * num + num2 * num2 <= r * r;
	}

	internal static bool RingAt(float x, float y, float cx, float cy, float r, float t)
	{
		return Math.Abs((float)Math.Sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)) - r) <= t / 2f;
	}

	internal static bool Box(float x, float y, float cx, float cy, float hw, float hh, float r)
	{
		return BoxSdf(x - cx, y - cy, hw, hh, r) <= 0f;
	}

	internal static bool InTri(float x, float y, float ax, float ay, float bx, float by, float cx, float cy)
	{
		float num = (x - bx) * (ay - by) - (ax - bx) * (y - by);
		float num2 = (x - cx) * (by - cy) - (bx - cx) * (y - cy);
		float num3 = (x - ax) * (cy - ay) - (cx - ax) * (y - ay);
		bool flag = num < 0f || num2 < 0f || num3 < 0f;
		bool flag2 = num > 0f || num2 > 0f || num3 > 0f;
		return !(flag && flag2);
	}

	private static float[] MakeStar()
	{
		float[] array = new float[20];
		for (int i = 0; i < 10; i++)
		{
			double num = Math.PI / 2.0 + (double)i * Math.PI / 5.0;
			double num2 = ((i % 2 == 0) ? 0.92 : 0.4);
			array[i * 2] = (float)(Math.Cos(num) * num2);
			array[i * 2 + 1] = (float)(Math.Sin(num) * num2) - 0.06f;
		}
		return array;
	}

	internal static bool InStar(float x, float y)
	{
		bool flag = false;
		int num = 0;
		int num2 = 9;
		while (num < 10)
		{
			float num3 = StarPts[num * 2];
			float num4 = StarPts[num * 2 + 1];
			float num5 = StarPts[num2 * 2];
			float num6 = StarPts[num2 * 2 + 1];
			if (num4 > y != num6 > y && x < (num5 - num3) * (y - num4) / (num6 - num4) + num3)
			{
				flag = !flag;
			}
			num2 = num++;
		}
		return flag;
	}

	internal static float StarEdge(float x, float y)
	{
		float num = float.MaxValue;
		int num2 = 0;
		int num3 = 9;
		while (num2 < 10)
		{
			float num4 = StarPts[num3 * 2];
			float num5 = StarPts[num3 * 2 + 1];
			float num6 = StarPts[num2 * 2];
			float num7 = StarPts[num2 * 2 + 1];
			float num8 = x - num4;
			float num9 = y - num5;
			float num10 = num6 - num4;
			float num11 = num7 - num5;
			float num12 = Clamp01((num8 * num10 + num9 * num11) / (num10 * num10 + num11 * num11));
			float num13 = num8 - num10 * num12;
			float num14 = num9 - num11 * num12;
			num = Math.Min(num, num13 * num13 + num14 * num14);
			num3 = num2++;
		}
		return (float)Math.Sqrt(num);
	}

	internal static Pic NamedIcon(string name, int size)
	{
		Rgba white = Rgba.White;
		return name switch
		{
			"person" => Icon(size, (float x, float y) => Disc(x, y, 0f, 0.38f, 0.36f) || (Box(x, y, 0f, -0.55f, 0.72f, 0.38f, 0.3f) && y < -0.18f), white), 
			"grid" => Icon(size, (float x, float y) => Box(x, y, -0.45f, 0.45f, 0.38f, 0.38f, 0.1f) || Box(x, y, 0.45f, 0.45f, 0.38f, 0.38f, 0.1f) || Box(x, y, -0.45f, -0.45f, 0.38f, 0.38f, 0.1f) || Box(x, y, 0.45f, -0.45f, 0.38f, 0.38f, 0.1f), white), 
			"star" => Icon(size, InStar, white), 
			"star_outline" => Icon(size, (float x, float y) => InStar(x, y) ? (StarEdge(x, y) <= 0.13f) : (StarEdge(x, y) <= 0.03f), white), 
			"clock" => Icon(size, (float x, float y) => RingAt(x, y, 0f, 0f, 0.78f, 0.18f) || Seg(x, y, 0f, 0f, 0f, 0.46f, 0.085f) || Seg(x, y, 0f, 0f, 0.34f, -0.2f, 0.085f), white), 
			"list" => Icon(size, (float x, float y) => Disc(x, y, -0.72f, 0.55f, 0.12f) || Disc(x, y, -0.72f, 0f, 0.12f) || Disc(x, y, -0.72f, -0.55f, 0.12f) || Seg(x, y, -0.38f, 0.55f, 0.8f, 0.55f, 0.1f) || Seg(x, y, -0.38f, 0f, 0.8f, 0f, 0.1f) || Seg(x, y, -0.38f, -0.55f, 0.8f, -0.55f, 0.1f), white), 
			"back" => Icon(size, (float x, float y) => Seg(x, y, -0.7f, 0f, 0.75f, 0f, 0.1f) || Seg(x, y, -0.7f, 0f, -0.2f, 0.5f, 0.1f) || Seg(x, y, -0.7f, 0f, -0.2f, -0.5f, 0.1f), white), 
			"gear" => Icon(size, delegate(float x, float y)
			{
				float num = (float)Math.Sqrt(x * x + y * y);
				if (num >= 0.3f && num <= 0.66f)
				{
					return true;
				}
				for (int i = 0; i < 8; i++)
				{
					double num2 = (double)i * Math.PI / 4.0;
					float num3 = (float)Math.Cos(num2);
					float num4 = (float)Math.Sin(num2);
					float x2 = x * num3 + y * num4;
					float y2 = (0f - x) * num4 + y * num3;
					if (Box(x2, y2, 0.74f, 0f, 0.2f, 0.15f, 0.06f))
					{
						return true;
					}
				}
				return false;
			}, white), 
			"search" => Icon(size, (float x, float y) => RingAt(x, y, -0.15f, 0.15f, 0.52f, 0.17f) || Seg(x, y, 0.24f, -0.24f, 0.78f, -0.78f, 0.1f), white), 
			"chevron_up" => Icon(size, (float x, float y) => Seg(x, y, -0.62f, -0.25f, 0f, 0.37f, 0.1f) || Seg(x, y, 0f, 0.37f, 0.62f, -0.25f, 0.1f), white), 
			"chevron_down" => Icon(size, (float x, float y) => Seg(x, y, -0.62f, 0.25f, 0f, -0.37f, 0.1f) || Seg(x, y, 0f, -0.37f, 0.62f, 0.25f, 0.1f), white), 
			"chevron_left" => Icon(size, (float x, float y) => Seg(x, y, 0.25f, -0.62f, -0.37f, 0f, 0.1f) || Seg(x, y, -0.37f, 0f, 0.25f, 0.62f, 0.1f), white), 
			"chevron_right" => Icon(size, (float x, float y) => Seg(x, y, -0.25f, -0.62f, 0.37f, 0f, 0.1f) || Seg(x, y, 0.37f, 0f, -0.25f, 0.62f, 0.1f), white), 
			"check" => Icon(size, (float x, float y) => Seg(x, y, -0.6f, 0.02f, -0.18f, -0.42f, 0.13f) || Seg(x, y, -0.18f, -0.42f, 0.62f, 0.45f, 0.13f), white), 
			"close" => Icon(size, (float x, float y) => Seg(x, y, -0.62f, -0.62f, 0.62f, 0.62f, 0.07f) || Seg(x, y, -0.62f, 0.62f, 0.62f, -0.62f, 0.07f), white), 
			"eye" => Icon(size, delegate(float x, float y)
			{
				float num = x * x / 0.81f + y * y / 0.25f;
				return (num <= 1f && num >= 0.62f) || Disc(x, y, 0f, 0f, 0.24f);
			}, white), 
			"play" => Icon(size, (float x, float y) => InTri(x, y, -0.48f, 0.72f, -0.48f, -0.72f, 0.78f, 0f), white), 
			"download" => Icon(size, (float x, float y) => Seg(x, y, 0f, 0.78f, 0f, -0.28f, 0.11f) || Seg(x, y, 0f, -0.32f, -0.42f, 0.1f, 0.11f) || Seg(x, y, 0f, -0.32f, 0.42f, 0.1f, 0.11f) || Seg(x, y, -0.7f, -0.74f, 0.7f, -0.74f, 0.11f), white), 
			"dice" => Icon(size, (float x, float y) => (Box(x, y, 0f, 0f, 0.84f, 0.84f, 0.26f) && !Box(x, y, 0f, 0f, 0.66f, 0.66f, 0.12f)) || Disc(x, y, 0f, 0f, 0.13f) || Disc(x, y, -0.34f, 0.34f, 0.13f) || Disc(x, y, 0.34f, 0.34f, 0.13f) || Disc(x, y, -0.34f, -0.34f, 0.13f) || Disc(x, y, 0.34f, -0.34f, 0.13f), white), 
			"map" => Icon(size, delegate(float x, float y)
			{
				if (x < -0.86f || x > 0.86f)
				{
					return false;
				}
				float num = 0.62f + ((x < -0.29f) ? ((x + 0.86f) / 0.57f * 0.16f) : ((x < 0.29f) ? (0.16f - (x + 0.29f) / 0.58f * 0.16f) : ((x - 0.29f) / 0.57f * 0.16f)));
				float num2 = num - 1.32f;
				if (y > num || y < num2)
				{
					return false;
				}
				return Math.Abs(x + 0.29f) > 0.045f && Math.Abs(x - 0.29f) > 0.045f;
			}, white), 
			"cube" => Icon(size, (float x, float y) => Seg(x, y, 0f, 0.82f, 0.74f, 0.42f, 0.09f) || Seg(x, y, 0.74f, 0.42f, 0.74f, -0.42f, 0.09f) || Seg(x, y, 0.74f, -0.42f, 0f, -0.82f, 0.09f) || Seg(x, y, 0f, -0.82f, -0.74f, -0.42f, 0.09f) || Seg(x, y, -0.74f, -0.42f, -0.74f, 0.42f, 0.09f) || Seg(x, y, -0.74f, 0.42f, 0f, 0.82f, 0.09f) || Seg(x, y, -0.74f, 0.42f, 0f, 0f, 0.09f) || Seg(x, y, 0f, 0f, 0.74f, 0.42f, 0.09f) || Seg(x, y, 0f, 0f, 0f, -0.82f, 0.09f), white), 
			"spark" => Icon(size, delegate(float x, float y)
			{
				float num = Math.Abs(x);
				float num2 = Math.Abs(y);
				return (float)Math.Sqrt(num) + (float)Math.Sqrt(num2) <= 0.95f;
			}, white), 
			"diamond" => Icon(size, (float x, float y) => (Math.Abs(x) + Math.Abs(y) <= 0.82f && !(Math.Abs(x) + Math.Abs(y) <= 0.5f)) || Math.Abs(x) + Math.Abs(y) <= 0.22f, white), 
			"heart" => Icon(size, (float x, float y) => Disc(x, y, -0.36f, 0.28f, 0.4f) || Disc(x, y, 0.36f, 0.28f, 0.4f) || InTri(x, y, -0.74f, 0.12f, 0.74f, 0.12f, 0f, -0.8f), white), 
			"user" => Icon(size, (float x, float y) => Disc(x, y, 0f, 0.42f, 0.32f) || (Disc(x, y, 0f, -0.62f, 0.68f) && y > -0.78f && y < -0.12f), white), 
			_ => Icon(size, (float x, float y) => Disc(x, y, 0f, 0f, 0.5f), white), 
		};
	}

	internal static float Clamp01(float v)
	{
		if (!(v < 0f))
		{
			if (!(v > 1f))
			{
				return v;
			}
			return 1f;
		}
		return 0f;
	}

	internal static Pic VGradient(int w, int h, Rgba top, Rgba bottom)
	{
		Pic pic = new Pic(w, h);
		for (int i = 0; i < h; i++)
		{
			float t = ((h > 1) ? (((float)i + 0.5f) / (float)h) : 0f);
			Rgba c = Rgba.Lerp(bottom, top, t);
			for (int j = 0; j < w; j++)
			{
				Put(pic, j, i, c, 1f);
			}
		}
		return pic;
	}

	internal static Pic VignetteGlow(int w, int h, float radius)
	{
		Pic pic = new Pic(w, h);
		float num = (float)w / 2f;
		float num2 = (float)h / 2f;
		for (int i = 0; i < h; i++)
		{
			for (int j = 0; j < w; j++)
			{
				float num3 = (float)j + 0.5f - num;
				float num4 = (float)i + 0.5f - num2;
				float num5 = Clamp01(0.5f - BoxSdf(num3, num4, num, num2, radius));
				float num6 = num3 / num;
				float num7 = num4 / num2;
				float num8 = Clamp01((Clamp01((float)Math.Sqrt((num6 * num6 + num7 * num7) / 2f)) - 0.12f) / 0.88f);
				num8 = num8 * num8 * (3f - 2f * num8);
				Put(pic, j, i, new Rgba(1f, 1f, 1f), num8 * num5);
			}
		}
		return pic;
	}

	internal static Pic MapArt(int w, int h)
	{
		Pic pic = new Pic(w, h);
		for (int i = 0; i < h; i++)
		{
			for (int j = 0; j < w; j++)
			{
				float num = ((float)j + 0.5f) / (float)w;
				float num2 = ((float)i + 0.5f) / (float)h;
				float num3 = 0.55f + 0.45f * Clamp01(1.15f - (num * 0.75f + (1f - num2) * 0.85f));
				double num4 = Math.Sin((double)num * 7.1 + 1.3) * 0.5 + Math.Cos((double)num2 * 5.3 - (double)num * 2.2) * 0.6 + Math.Sin((double)(num + num2) * 9.7) * 0.18;
				double num5 = num4 * 6.0 - Math.Floor(num4 * 6.0);
				float num6 = (float)Math.Max(0.0, 1.0 - Math.Abs(num5 - 0.5) * 2.0 / 0.16);
				float num7 = Clamp01(num3 * (1f - 0.13f * num6));
				float num8 = num - 0.5f;
				float num9 = num2 - 0.5f;
				num7 *= 1f - 0.35f * Clamp01((num8 * num8 + num9 * num9) * 2.2f);
				Put(pic, j, i, new Rgba(num7, num7, num7), 1f);
			}
		}
		return pic;
	}

	private static void Put(Pic pic, int x, int y, Rgba c, float cov)
	{
		int num = (y * pic.W + x) * 4;
		pic.Px[num] = ToByte(c.R);
		pic.Px[num + 1] = ToByte(c.G);
		pic.Px[num + 2] = ToByte(c.B);
		pic.Px[num + 3] = ToByte(c.A * cov);
	}

	private static byte ToByte(float v)
	{
		if (v <= 0f)
		{
			return 0;
		}
		if (v >= 1f)
		{
			return byte.MaxValue;
		}
		return (byte)(int)(v * 255f + 0.5f);
	}
}
internal static class Bank
{
	private static Task<Dictionary<string, Pic>> _making;

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

	private static Rgba W => Rgba.White;

	internal static void Prepare()
	{
		if (_making == null)
		{
			_making = Task.Run(() => MakeAll());
		}
	}

	private static Dictionary<string, Pic> MakeAll()
	{
		Stopwatch stopwatch = Stopwatch.StartNew();
		Dictionary<string, Pic> dictionary = new Dictionary<string, Pic>();
		HudRect panel = MenuLayout.Panel;
		HudRect titleBar = MenuLayout.TitleBar;
		HudRect sidebar = MenuLayout.Sidebar;
		dictionary["panel"] = Shapes.RoundRect((int)panel.W, (int)panel.H, 18f, W);
		dictionary["titlebar"] = Shapes.RoundRect((int)(titleBar.W * 2f), (int)(titleBar.H * 2f), 36f, 36f, 0f, 0f, W, W);
		dictionary["sidebar"] = Shapes.RoundRect((int)sidebar.W, (int)sidebar.H, 0f, 0f, 0f, 18f, W, W);
		dictionary["card"] = Shapes.RoundRect(464, 504, 22f, W);
		dictionary["card_outline"] = Shapes.RoundRectOutline(464, 504, 22f, 4f, W);
		dictionary["row"] = Shapes.RoundRect(1480, 144, 24f, W);
		dictionary["bigframe"] = Shapes.RoundRect((int)(MenuLayout.BigPic.W + 8f), (int)(MenuLayout.BigPic.H + 8f), 14f, W);
		dictionary["shade"] = Shapes.VGradient(4, 64, new Rgba(0f, 0f, 0f, 0f), new Rgba(0f, 0f, 0f, 0.78f));
		dictionary["shade_top"] = Shapes.VGradient(4, 64, new Rgba(0f, 0f, 0f, 0.55f), new Rgba(0f, 0f, 0f, 0f));
		dictionary["mapart"] = Shapes.MapArt(384, 216);
		dictionary["glow"] = Shapes.VignetteGlow(384, 282, 7f);
		dictionary["aurora"] = Shapes.VignetteGlow(512, 384, 9f);
		dictionary["soft"] = Shapes.VignetteGlow(256, 256, 5f);
		dictionary["dot"] = Shapes.Circle(24, W);
		dictionary["cap"] = Cap(24);
		string[] iconNames = Shapes.IconNames;
		foreach (string text in iconNames)
		{
			dictionary["icon_" + text] = Shapes.NamedIcon(text, 64);
		}
		stopwatch.Stop();
		Log.Info("Menu pictures drawn in the background: " + dictionary.Count + " in " + stopwatch.Elapsed.TotalMilliseconds.ToString("0") + " ms.");
		return dictionary;
	}

	private static Pic Cap(int size)
	{
		Pic pic = new Pic(size, size);
		float num = size;
		for (int i = 0; i < size; i++)
		{
			for (int j = 0; j < size; j++)
			{
				float num2 = num - ((float)j + 0.5f);
				float num3 = num - ((float)i + 0.5f);
				float num4 = (float)Math.Sqrt(num2 * num2 + num3 * num3) - num;
				float num5 = Shapes.Clamp01(0.5f + num4);
				int num6 = (i * size + j) * 4;
				pic.Px[num6] = byte.MaxValue;
				pic.Px[num6 + 1] = byte.MaxValue;
				pic.Px[num6 + 2] = byte.MaxValue;
				pic.Px[num6 + 3] = (byte)(num5 * 255f + 0.5f);
			}
		}
		return pic;
	}

	internal static Texture2D Get(string name)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		if (_tex.TryGetValue(name, out var value) && (Object)value != (Object)null)
		{
			return value;
		}
		Prepare();
		Dictionary<string, Pic> result;
		try
		{
			result = _making.Result;
		}
		catch (Exception e)
		{
			Log.Error("The picture bank failed to build", e);
			return null;
		}
		if (!result.TryGetValue(name, out var value2))
		{
			Log.Warn("No menu picture called " + name);
			return null;
		}
		value = ToTexture(value2);
		_tex[name] = value;
		return value;
	}

	internal static Texture2D Round(float w, float h, float radius)
	{
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Expected O, but got Unknown
		int num = Math.Max(2, (int)Math.Round(w * 2f));
		int num2 = Math.Max(2, (int)Math.Round(h * 2f));
		string key = "rr_" + num + "_" + num2 + "_" + (int)(radius * 2f);
		if (_tex.TryGetValue(key, out var value) && (Object)value != (Object)null)
		{
			return value;
		}
		float r = Math.Min(radius * 2f, (float)Math.Min(num, num2) / 2f);
		value = ToTexture(Shapes.RoundRect(num, num2, r, Rgba.White));
		_tex[key] = value;
		return value;
	}

	internal static Texture2D RoundOutline(float w, float h, float radius, float thickness = 2.5f)
	{
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Expected O, but got Unknown
		float num = ((w * h > 400000f) ? 1f : 2f);
		int num2 = Math.Max(4, (int)Math.Round(w * num));
		int num3 = Math.Max(4, (int)Math.Round(h * num));
		int num4 = Math.Max(1, (int)Math.Round(radius * num));
		int num5 = Math.Max(2, (int)Math.Round(thickness * num));
		string key = "ro_" + num2 + "_" + num3 + "_" + num4 + "_" + num5;
		if (_tex.TryGetValue(key, out var value) && (Object)value != (Object)null)
		{
			return value;
		}
		float r = Math.Min(num4, (float)Math.Min(num2, num3) / 2f);
		value = ToTexture(Shapes.RoundRectOutline(num2, num3, r, Math.Max(1.5f, num5), Rgba.White));
		_tex[key] = value;
		return value;
	}

	internal static Texture2D ToTexture(Pic p)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Expected O, but got Unknown
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(p.W, p.H, (TextureFormat)4, false);
		Color32[] array = (Color32[])(object)new Color32[p.W * p.H];
		for (int i = 0; i < array.Length; i++)
		{
			int num = i * 4;
			array[i] = new Color32
			{
				r = p.Px[num],
				g = p.Px[num + 1],
				b = p.Px[num + 2],
				a = p.Px[num + 3]
			};
		}
		val.SetPixels32(new Il2CppStructArray<Color32>(array), 0);
		val.Apply(false, false);
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Object)val).hideFlags = (HideFlags)32;
		return val;
	}

	internal static void Clear()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Expected O, but got Unknown
		foreach (Texture2D value in _tex.Values)
		{
			try
			{
				if ((Object)value != (Object)null)
				{
					Object.Destroy((Object)value);
				}
			}
			catch
			{
			}
		}
		_tex.Clear();
	}
}
internal static class Favorites
{
	private static readonly HashSet<string> Keys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private static string FilePath => Path.Combine(MelonEnvironment.UserDataDirectory, "BoneMenuPlus", "favorites.json");

	internal static int Count => Keys.Count;

	internal static void Load()
	{
		Keys.Clear();
		try
		{
			if (!File.Exists(FilePath))
			{
				return;
			}
			string[] array = JsonSerializer.Deserialize<string[]>(File.ReadAllText(FilePath));
			if (array == null)
			{
				return;
			}
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (!string.IsNullOrWhiteSpace(text))
				{
					Keys.Add(text);
				}
			}
			Log.Info("Read " + Keys.Count + " favourite mods.");
		}
		catch (Exception ex)
		{
			Log.Warn("Reading the favourites failed: " + ex.Message);
		}
	}

	internal static bool Has(string key)
	{
		if (!string.IsNullOrEmpty(key))
		{
			return Keys.Contains(key);
		}
		return false;
	}

	internal static bool Toggle(string key)
	{
		if (string.IsNullOrEmpty(key))
		{
			return false;
		}
		bool num = !Keys.Contains(key);
		if (num)
		{
			Keys.Add(key);
		}
		else
		{
			Keys.Remove(key);
		}
		Save();
		return num;
	}

	private static void Save()
	{
		try
		{
			string directoryName = Path.GetDirectoryName(FilePath);
			if (!string.IsNullOrEmpty(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
			string[] array = new string[Keys.Count];
			Keys.CopyTo(array);
			Array.Sort(array, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
			File.WriteAllText(FilePath, JsonSerializer.Serialize(array, new JsonSerializerOptions
			{
				WriteIndented = true
			}));
		}
		catch (Exception ex)
		{
			Log.Warn("Saving the favourites failed: " + ex.Message);
		}
	}
}
internal sealed class Keyboard
{
	private static readonly string[] Rows = new string[4] { "1234567890", "QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM" };

	private const float KeySize = 62f;

	private const float KeyGap = 8f;

	private readonly GameObject _root;

	internal bool Visible
	{
		get
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			if ((Object)_root != (Object)null)
			{
				return _root.activeSelf;
			}
			return false;
		}
	}

	internal GameObject Root => _root;

	internal Keyboard(Transform parent, Vector2 topCenter, Action<char> onChar, Action onBackspace, Action onSpace, Action onClear)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_030e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0313: Unknown result type (might be due to invalid IL or missing references)
		//IL_0318: Unknown result type (might be due to invalid IL or missing references)
		//IL_031d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0362: Unknown result type (might be due to invalid IL or missing references)
		//IL_0367: Unknown result type (might be due to invalid IL or missing references)
		//IL_036c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0371: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0280: Unknown result type (might be due to invalid IL or missing references)
		//IL_0285: Unknown result type (might be due to invalid IL or missing references)
		//IL_028a: Unknown result type (might be due to invalid IL or missing references)
		//IL_028f: Unknown result type (might be due to invalid IL or missing references)
		_root = new GameObject("BMP_Keyboard");
		_root.layer = Paint.Layer;
		_root.transform.SetParent(parent, false);
		RectTransform obj = _root.AddComponent<RectTransform>();
		obj.anchorMin = new Vector2(0.5f, 0.5f);
		obj.anchorMax = new Vector2(0.5f, 0.5f);
		obj.sizeDelta = Vector2.zero;
		obj.anchoredPosition = topCenter;
		Image obj2 = ((Component)Paint.Node(_root.transform, "Dim", Vector2.zero, new Vector2(980f, 720f))).gameObject.AddComponent<Image>();
		((Graphic)obj2).color = new Color(0.02f, 0.03f, 0.05f, 0.72f);
		((Graphic)obj2).raycastTarget = false;
		float w = 740f;
		float h = 386f;
		HudRect r = new HudRect(0f, -140f, w, h);
		Paint.Rounded(_root.transform, "KeyboardShadow", new HudRect(r.X + 6f, r.Y - 10f, r.W + 14f, r.H + 12f), 22f, new Color(0f, 0f, 0f, 0.45f));
		Paint.Rounded(_root.transform, "KeyboardPlate", r, 18f, Theme.TitleBar);
		Paint.Frame(_root.transform, "KeyboardFrame", r, 18f, Theme.OutlineLine);
		float num = r.Top - 56f;
		string[] rows = Rows;
		TMP_Text text2;
		foreach (string text in rows)
		{
			float num2 = (0f - ((float)text.Length * 62f + (float)(text.Length - 1) * 8f)) / 2f + 31f;
			for (int j = 0; j < text.Length; j++)
			{
				char c = text[j];
				Paint.TextBtn(_root.transform, "Key_" + c, new HudRect(num2 + (float)j * 70f, num, 62f, 62f), 10f, c.ToString(), 26f, Theme.Button, Theme.ButtonHover, Theme.AccentDeep, Theme.Text, delegate
				{
					onChar(c);
				}, out text2);
			}
			num -= 70f;
		}
		Paint.TextBtn(_root.transform, "Key_Backspace", new HudRect(-244f, num, 208f, 62f), 10f, "BACKSPACE", 18f, Theme.Button, Theme.ButtonHover, Theme.AccentDeep, Theme.Text, onBackspace, out text2);
		Paint.TextBtn(_root.transform, "Key_Space", new HudRect(0f, num, 252f, 62f), 10f, "SPACE", 18f, Theme.Button, Theme.ButtonHover, Theme.AccentDeep, Theme.Text, onSpace, out text2);
		Paint.TextBtn(_root.transform, "Key_Clear", new HudRect(244f, num, 208f, 62f), 10f, "CLEAR", 18f, Theme.Danger, Theme.DangerHover, Theme.DangerHover, Theme.Text, onClear, out text2);
		_root.SetActive(false);
	}

	internal void Show()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		if (!((Object)_root == (Object)null))
		{
			_root.SetActive(true);
			_root.transform.SetAsLastSibling();
		}
	}

	internal void Hide()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		if ((Object)_root != (Object)null)
		{
			_root.SetActive(false);
		}
	}

	internal void Destroy()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		if ((Object)_root != (Object)null)
		{
			Object.Destroy((Object)_root);
		}
	}
}
internal sealed class LaserPointer
{
	private const float RefindEvery = 3f;

	private const float Reach = 8f;

	private readonly List<LaserCursor> _cursors = new List<LaserCursor>();

	private readonly Dictionary<int, bool> _press = new Dictionary<int, bool>();

	private GameObject _hover;

	private Button _hoverButton;

	private float _nextFind;

	private PointerEventData _data;

	private int _logs;

	private bool _loggedHit;

	private bool _loggedColliderCount;

	private bool _loggedPressMiss;

	internal void Update(Transform root)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Expected O, but got Unknown
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)root == (Object)null)
		{
			Clear();
			return;
		}
		float unscaledTime = Time.unscaledTime;
		if (unscaledTime >= _nextFind || _cursors.Count == 0)
		{
			_nextFind = unscaledTime + 3f;
			Find();
		}
		if (!_loggedColliderCount)
		{
			_loggedColliderCount = true;
			try
			{
				Log.Info("Laser pointer sees " + ((Component)root).GetComponentsInChildren<Collider>(true).Length + " collider(s) under the panel.");
			}
			catch (Exception e)
			{
				WarnOnce("collider count", e);
			}
		}
		GameObject hover = null;
		bool flag = false;
		foreach (LaserCursor cursor in _cursors)
		{
			if ((Object)cursor == (Object)null)
			{
				continue;
			}
			bool flag2;
			try
			{
				flag2 = cursor.m_IsTrigger || cursor.m_IsTriggeredDown || ControllerPressed(cursor);
			}
			catch
			{
				continue;
			}
			Ray ray;
			try
			{
				ray = cursor.ray;
			}
			catch
			{
				continue;
			}
			Vector3 direction = ((Ray)(ref ray)).direction;
			if (((Vector3)(ref direction)).sqrMagnitude < 1E-06f)
			{
				((Ray)(ref ray))..ctor(((Component)cursor).transform.position, ((Component)cursor).transform.forward);
			}
			GameObject val = Pick(ray, root);
			if ((Object)(object)val == (Object)null)
			{
				try
				{
					val = Pick(new Ray(((Component)cursor).transform.position, ((Component)cursor).transform.forward), root);
				}
				catch
				{
				}
			}
			int instanceID = ((Object)cursor).GetInstanceID();
			_press.TryGetValue(instanceID, out var value);
			_press[instanceID] = flag2;
			if ((Object)(object)val != (Object)null)
			{
				hover = val;
			}
			if (flag2 && !value)
			{
				if ((Object)(object)val != (Object)null)
				{
					flag = true;
				}
				else if (!_loggedPressMiss)
				{
					_loggedPressMiss = true;
					Log.Info("Laser pointer saw a trigger press with nothing under the beam.");
				}
			}
		}
		SetHover(hover);
		if (flag)
		{
			Click();
		}
	}

	internal void Clear()
	{
		SetHover(null);
		_press.Clear();
	}

	private void Find()
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		_cursors.Clear();
		LaserCursor[] array = Il2CppArrayBase<LaserCursor>.op_Implicit(Object.FindObjectsOfType<LaserCursor>(true));
		foreach (LaserCursor val in array)
		{
			if ((Object)val != (Object)null)
			{
				_cursors.Add(val);
			}
		}
		if (_logs++ < 4)
		{
			Log.Info("Laser pointer found " + _cursors.Count + " laser cursor(s).");
		}
	}

	private GameObject Pick(Ray ray, Transform root)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		RaycastHit[] array;
		try
		{
			array = Il2CppArrayBase<RaycastHit>.op_Implicit((Il2CppArrayBase<RaycastHit>)(object)Physics.RaycastAll(ray, 8f, -1, (QueryTriggerInteraction)2));
		}
		catch (Exception ex)
		{
			if (_logs++ < 4)
			{
				Log.Warn("Laser raycast failed: " + ex.Message);
			}
			return null;
		}
		GameObject val = null;
		float num = float.MaxValue;
		RaycastHit[] array2 = array;
		for (int i = 0; i < array2.Length; i++)
		{
			RaycastHit val2 = array2[i];
			Transform transform = ((RaycastHit)(ref val2)).transform;
			if (!((Object)transform == (Object)null) && transform.IsChildOf(root))
			{
				float distance = ((RaycastHit)(ref val2)).distance;
				if (distance < num)
				{
					num = distance;
					val = ((Component)transform).gameObject;
				}
			}
		}
		if ((Object)(object)val != (Object)null && !_loggedHit)
		{
			_loggedHit = true;
			Log.Info("Laser pointer hit \"" + ((Object)val).name + "\" at " + num.ToString("0.000") + " m.");
		}
		return val;
	}

	private PointerEventData Data()
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Expected O, but got Unknown
		if (_data == null)
		{
			try
			{
				_data = new PointerEventData((EventSystem)null);
			}
			catch
			{
				return null;
			}
		}
		return _data;
	}

	private void SetHover(GameObject next)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected O, but got Unknown
		//IL_0016: Expected O, but got Unknown
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Expected O, but got Unknown
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Expected O, but got Unknown
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Expected O, but got Unknown
		if ((Object)next == (Object)_hover)
		{
			return;
		}
		Button hoverButton = _hoverButton;
		_hover = next;
		_hoverButton = null;
		if ((Object)hoverButton != (Object)null)
		{
			try
			{
				((Selectable)hoverButton).OnPointerExit(Data());
			}
			catch (Exception e)
			{
				WarnOnce("pointer exit", e);
			}
		}
		if ((Object)next == (Object)null)
		{
			return;
		}
		try
		{
			_hoverButton = next.GetComponentInParent<Button>();
		}
		catch (Exception e2)
		{
			WarnOnce("button lookup", e2);
		}
		if (!((Object)_hoverButton != (Object)null))
		{
			return;
		}
		try
		{
			((Selectable)_hoverButton).OnPointerEnter(Data());
		}
		catch (Exception e3)
		{
			WarnOnce("pointer enter", e3);
		}
	}

	private bool ControllerPressed(LaserCursor cursor)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Expected O, but got Unknown
		try
		{
			Il2CppReferenceArray<BaseController> controllers = cursor.controllers;
			if (controllers != null)
			{
				for (int i = 0; i < ((Il2CppArrayBase<BaseController>)(object)controllers).Length; i++)
				{
					BaseController val = ((Il2CppArrayBase<BaseController>)(object)controllers)[i];
					if ((Object)val != (Object)null && (val._primaryInteractionButton || val._primaryInteractionButtonDown))
					{
						return true;
					}
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private void Click()
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Expected O, but got Unknown
		Button hoverButton = _hoverButton;
		if ((Object)hoverButton == (Object)null)
		{
			return;
		}
		try
		{
			Log.Info("Laser pointer click on \"" + ((Object)hoverButton).name + "\".");
		}
		catch
		{
		}
		try
		{
			((Selectable)hoverButton).OnPointerDown(Data());
			((Selectable)hoverButton).OnPointerUp(Data());
			hoverButton.OnPointerClick(Data());
		}
		catch (Exception e)
		{
			WarnOnce("pointer click", e);
		}
	}

	private void WarnOnce(string what, Exception e)
	{
		if (_logs++ < 6)
		{
			Log.Warn("Laser pointer " + what + " failed: " + e.Message);
		}
	}
}
internal static class Log
{
	private const int MaxLines = 8000;

	private static string _path;

	private static int _lines;

	private static readonly object Gate = new object();

	internal static void Init()
	{
		try
		{
			string text = Path.Combine(MelonEnvironment.UserDataDirectory, "BoneMenuPlus");
			Directory.CreateDirectory(text);
			_path = Path.Combine(text, "log.txt");
			File.WriteAllText(_path, "BoneMenu Plus log, started " + DateTime.Now.ToString() + Environment.NewLine);
		}
		catch
		{
			_path = null;
		}
	}

	internal static void Info(string msg)
	{
		Write("INFO  ", msg);
	}

	internal static void Warn(string msg)
	{
		Write("WARN  ", msg);
	}

	internal static void Error(string msg, Exception e)
	{
		Write("ERROR ", msg + ((e != null) ? (" :: " + e) : ""));
	}

	private static void Write(string level, string msg)
	{
		if (_path == null)
		{
			return;
		}
		try
		{
			lock (Gate)
			{
				if (_lines++ < 8000)
				{
					File.AppendAllText(_path, DateTime.Now.ToString("HH:mm:ss.fff") + " " + level + msg + Environment.NewLine);
				}
			}
		}
		catch
		{
		}
	}
}
internal static class MenuLayout
{
	internal const float DesignW = 980f;

	internal const float DesignH = 720f;

	internal static readonly HudRect Panel = new HudRect(0f, 0f, 980f, 720f);

	internal static readonly HudRect TitleBar = new HudRect(0f, 333f, 980f, 54f);

	internal static readonly HudRect TitleIcon = new HudRect(-464f, 333f, 28f, 28f);

	internal static readonly HudRect TitleText = new HudRect(-272f, 341f, 340f, 26f);

	internal static readonly HudRect SubTitle = new HudRect(-272f, 318f, 340f, 14f);

	internal static readonly HudRect Status = new HudRect(110f, 333f, 330f, 34f);

	internal static readonly HudRect Search = new HudRect(60f, 333f, 250f, 36f);

	internal static readonly HudRect Gear = new HudRect(210f, 333f, 48f, 36f);

	internal static readonly HudRect Classic = new HudRect(300f, 333f, 120f, 38f);

	internal static readonly HudRect Close = new HudRect(420f, 333f, 44f, 40f);

	internal static readonly HudRect FooterRight = new HudRect(180f, -347f, 300f, 16f);

	internal static readonly HudRect Toast = new HudRect(0f, -302f, 560f, 44f);

	internal static readonly HudRect Sidebar = new HudRect(-375f, -27f, 230f, 666f);

	internal static readonly HudRect SideTitle = new HudRect(-375f, 285f, 206f, 26f);

	internal static readonly HudRect Separator = new HudRect(-375f, -26f, 198f, 2f);

	internal static readonly HudRect Tip = new HudRect(-375f, -308f, 206f, 34f);

	internal static readonly HudRect GameMenu = new HudRect(-375f, -262f, 206f, 40f);

	internal const float CatX = -375f;

	internal const float CatW = 214f;

	internal const float CatH = 40f;

	internal const float CatGap = 6f;

	internal const float CatTop = 246f;

	internal static readonly HudRect CatBar = new HudRect(-105f, 0f, 4f, 24f);

	internal static readonly HudRect CatLabel = new HudRect(-18f, 0f, 132f, 24f);

	internal static readonly HudRect CatCount = new HudRect(81f, 0f, 40f, 22f);

	internal const float MainX = 120f;

	internal const float MainW = 740f;

	internal const float MainTop = 238f;

	internal const int CardCols = 3;

	internal const int CardRows = 2;

	internal const float CardW = 232f;

	internal const float CardH = 252f;

	internal const float GridLeft = -240f;

	internal const float Gap = 12f;

	internal const int RowsPerPage = 6;

	internal const float RowW = 740f;

	internal const float RowH = 72f;

	internal const float RowGap = 8f;

	internal const float RowTop = 214f;

	internal static readonly HudRect BigPic = new HudRect(120f, 148f, 300f, 168f);

	internal static readonly HudRect Back = new HudRect(-188f, 272f, 124f, 46f);

	internal static readonly HudRect Crumb = new HudRect(140f, 276f, 480f, 28f);

	internal static readonly HudRect CrumbSub = new HudRect(140f, 250f, 480f, 18f);

	internal static readonly HudRect Refresh = new HudRect(-174f, 272f, 152f, 46f);

	internal static readonly HudRect CatTitle = new HudRect(134f, 274f, 370f, 28f);

	internal static readonly HudRect Prev = new HudRect(350f, 272f, 46f, 46f);

	internal static readonly HudRect PageText = new HudRect(406f, 274f, 64f, 30f);

	internal static readonly HudRect Next = new HudRect(464f, 272f, 46f, 46f);

	internal static readonly HudRect RPrev = new HudRect(350f, -318f, 46f, 42f);

	internal static readonly HudRect RPageText = new HudRect(406f, -316f, 64f, 30f);

	internal static readonly HudRect RNext = new HudRect(464f, -318f, 46f, 42f);

	internal static readonly HudRect CardPhoto = new HudRect(0f, 39f, 208f, 150f);

	internal static readonly HudRect CardTitle = new HudRect(9f, -50f, 190f, 24f);

	internal static readonly HudRect CardSub = new HudRect(9f, -74f, 198f, 18f);

	internal static readonly HudRect CardDot = new HudRect(CardPhoto.Left + 9f, -50f, 4f, 22f);

	internal static readonly HudRect CardInitials = new HudRect(0f, CardPhoto.Y, CardPhoto.W - 14f, 34f);

	internal static readonly HudRect CardStrip = new HudRect(0f, -115f, 188f, 3f);

	internal static readonly HudRect CardStar = new HudRect(92f, 102f, 36f, 36f);

	internal static readonly HudRect EmptyIcon = new HudRect(120f, 28f, 58f, 58f);

	internal static readonly HudRect Footer = new HudRect(-375f, -347f, 206f, 16f);

	internal const float RowRight = 474f;

	internal static float CatY(int i)
	{
		return 246f - (float)i * 46f;
	}

	internal static float CardX(int col)
	{
		return -124f + (float)col * 244f;
	}

	internal static float CardY(int row)
	{
		return 112f - (float)row * 264f;
	}

	internal static float RowY(int i)
	{
		return 178f - (float)i * 80f;
	}

	internal static HudRect Row(int i)
	{
		return new HudRect(120f, RowY(i), 740f, 72f);
	}

	internal static HudRect RowBar(int i)
	{
		return new HudRect(-356f, 0f, 4f, 44f);
	}

	internal static HudRect RowName(int i)
	{
		return new HudRect(-188f, 11f, 300f, 24f);
	}

	internal static HudRect RowValue(int i)
	{
		return new HudRect(-188f, -13f, 300f, 18f);
	}

	internal static HudRect RowAction(int i)
	{
		return new HudRect(299f, 0f, 110f, 44f);
	}

	internal static HudRect RowPlus(int i)
	{
		return new HudRect(332f, 0f, 44f, 44f);
	}

	internal static HudRect RowMinus(int i)
	{
		return new HudRect(282f, 0f, 44f, 44f);
	}

	internal static HudRect RowStepValue(int i)
	{
		return new HudRect(214f, 0f, 80f, 34f);
	}
}
internal sealed class MenuScreen
{
	private sealed class CardSlot
	{
		internal GameObject Go;

		internal Button Btn;

		internal RawImage Bg;

		internal RawImage Photo;

		internal RawImage Dot;

		internal RawImage Strip;

		internal TMP_Text Title;

		internal TMP_Text Sub;

		internal TMP_Text Initials;

		internal ModEntry Entry;

		internal Texture Cover;

		internal Button FavBtn;

		internal RawImage FavIcon;
	}

	private sealed class OptSlot
	{
		internal Button Btn;

		internal TMP_Text Label;

		internal TMP_Text Value;

		internal int Index;
	}

	private sealed class CatSlot
	{
		internal GameObject Go;

		internal Button Btn;

		internal RawImage Bar;

		internal RawImage CountBg;

		internal TMP_Text Label;

		internal TMP_Text Count;

		internal string Cat = "All";

		internal int State = -1;
	}

	private sealed class RowSlot
	{
		internal GameObject Go;

		internal RawImage Bg;

		internal RawImage Bar;

		internal TMP_Text Name;

		internal TMP_Text Value;

		internal Button Action;

		internal RawImage ActionBg;

		internal TMP_Text ActionText;

		internal Button Plus;

		internal Button Minus;

		internal TMP_Text StepValue;

		internal RawImage Knob;

		internal Element El;

		internal int Kind;
	}

	private const int KindLink = 0;

	private const int KindFunction = 1;

	private const int KindBool = 2;

	private const int KindStep = 3;

	private const int KindEnum = 4;

	private const int KindString = 5;

	private readonly Catalog _catalog = new Catalog();

	private readonly Covers _covers;

	private readonly CursorArea _cursorArea = new CursorArea();

	private readonly LaserPointer _pointer = new LaserPointer();

	private readonly List<CardSlot> _cards = new List<CardSlot>();

	private readonly List<CatSlot> _cats = new List<CatSlot>();

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

	private List<Element> _flat = new List<Element>();

	private float _nextFlat;

	private GUIMenu _host;

	private UiStyle _style = new UiStyle();

	private GameObject _root;

	private GameObject _homeView;

	private GameObject _detailView;

	private GameObject _rowHolder;

	private GameObject _catHolder;

	private GameObject _vanilla;

	private TMP_Text _title;

	private TMP_Text _sub;

	private TMP_Text _statusText;

	private RawImage _statusDot;

	private TMP_Text _homeCat;

	private TMP_Text _empty;

	private TMP_Text _emptyHint;

	private RawImage _emptyIcon;

	private TMP_Text _toast;

	private RawImage _toastBg;

	private RawImage _toastFrame;

	private float _toastUntil;

	private TMP_Text _searchText;

	private RawImage _searchFrame;

	private RawImage _backdrop;

	private RawImage _glow;

	private GameObject _settingsView;

	private CanvasGroup _group;

	private float _openAt;

	private bool _settings;

	private bool _gameMenu;

	private string _query = "";

	private Keyboard _keyboard;

	private readonly List<OptSlot> _options = new List<OptSlot>();

	private Texture2D _customTexture;

	private TMP_Text _pageText;

	private TMP_Text _crumb;

	private TMP_Text _crumbSub;

	private TMP_Text _tip;

	private TMP_Text _rPageText;

	private Button _prev;

	private Button _next;

	private Button _back;

	private Button _rPrev;

	private Button _rNext;

	private Page _page;

	private string _category = "All";

	private string _lastCatKey = "";

	private string _lastPageKey = "";

	private int _gridPage;

	private int _rowPage;

	private float _nextScan;

	private float _nextBuild;

	private float _scale = 1f;

	private bool _built;

	private bool _vanillaHidden;

	internal MenuScreen(string dataDirectory)
	{
		_covers = new Covers(dataDirectory);
		_catalog.LoadSettings();
		Favorites.Load();
	}

	internal void Tick(float now)
	{
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Expected O, but got Unknown
		//IL_00a5: 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_00b5: Expected O, but got Unknown
		//IL_00b5: Expected O, but got Unknown
		GUIMenu val = null;
		try
		{
			val = GUIMenu.Instance;
		}
		catch
		{
			val = null;
		}
		if (!((Object)(object)val != (Object)null) || !((Object)(object)((Component)val).gameObject != (Object)null) || !((Component)val).gameObject.activeInHierarchy || !Prefs.UseModUi)
		{
			Hide();
			return;
		}
		if (_gameMenu)
		{
			if ((Object)_root != (Object)null && _root.activeSelf)
			{
				_root.SetActive(false);
			}
			ShowVanilla();
			try
			{
				if (Menu.CurrentPage == BoneMenuPlusMod.OwnPage)
				{
					_gameMenu = false;
				}
				return;
			}
			catch
			{
				return;
			}
		}
		if ((!_built || (Object)_host != (Object)val) && now >= _nextBuild)
		{
			_nextBuild = now + 5f;
			Build(val);
		}
		if (_built)
		{
			if (!_root.activeSelf)
			{
				_root.SetActive(true);
			}
			HideVanilla();
			ShowCursor(now);
			_pointer.Update(_root.transform);
			if (now >= _nextScan)
			{
				_nextScan = now + 2f;
				Rescan();
			}
			SyncPage();
			Fit(val);
			Render(now);
		}
	}

	internal void Shutdown()
	{
		Teardown();
		_covers.Dispose();
	}

	private void ReadStyle(Transform host)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Expected O, but got Unknown
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Expected O, but got Unknown
		_style = new UiStyle();
		try
		{
			foreach (TMP_Text componentsInChild in ((Component)host).GetComponentsInChildren<TMP_Text>(true))
			{
				if (!((Object)componentsInChild == (Object)null))
				{
					_ = ((Component)componentsInChild).gameObject.layer;
					if (!((Object)componentsInChild.font == (Object)null))
					{
						_style.Font = componentsInChild.font;
						break;
					}
				}
			}
		}
		catch (Exception ex)
		{
			Log.Warn("Reading the menu font failed (default font used): " + ex.Message);
		}
		_style.Layer = 5;
	}

	private void Build(GUIMenu host)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Expected O, but got Unknown
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Expected O, but got Unknown
		//IL_0150: 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_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Expected O, but got Unknown
		//IL_024e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0265: Unknown result type (might be due to invalid IL or missing references)
		//IL_0294: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0311: Unknown result type (might be due to invalid IL or missing references)
		//IL_0359: Unknown result type (might be due to invalid IL or missing references)
		//IL_0378: Unknown result type (might be due to invalid IL or missing references)
		//IL_0393: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0413: Unknown result type (might be due to invalid IL or missing references)
		//IL_0418: Unknown result type (might be due to invalid IL or missing references)
		//IL_0422: Unknown result type (might be due to invalid IL or missing references)
		//IL_043d: Unknown result type (might be due to invalid IL or missing references)
		//IL_045e: Unknown result type (might be due to invalid IL or missing references)
		//IL_049a: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f3: Expected O, but got Unknown
		//IL_0504: Unknown result type (might be due to invalid IL or missing references)
		//IL_054b: Unknown result type (might be due to invalid IL or missing references)
		//IL_059b: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_05da: Unknown result type (might be due to invalid IL or missing references)
		//IL_062d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0681: Unknown result type (might be due to invalid IL or missing references)
		//IL_06b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_06b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_06bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_06c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_06ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_0724: Unknown result type (might be due to invalid IL or missing references)
		//IL_0738: Unknown result type (might be due to invalid IL or missing references)
		//IL_073d: Unknown result type (might be due to invalid IL or missing references)
		//IL_074f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0754: Unknown result type (might be due to invalid IL or missing references)
		//IL_0782: Unknown result type (might be due to invalid IL or missing references)
		//IL_0787: Unknown result type (might be due to invalid IL or missing references)
		//IL_078c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0791: Unknown result type (might be due to invalid IL or missing references)
		//IL_07c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_07de: Unknown result type (might be due to invalid IL or missing references)
		//IL_07e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_080f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0814: Unknown result type (might be due to invalid IL or missing references)
		//IL_085a: Unknown result type (might be due to invalid IL or missing references)
		//IL_087d: Unknown result type (might be due to invalid IL or missing references)
		//IL_089d: Unknown result type (might be due to invalid IL or missing references)
		//IL_08e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0902: Unknown result type (might be due to invalid IL or missing references)
		//IL_090d: Expected O, but got Unknown
		//IL_0913: Unknown result type (might be due to invalid IL or missing references)
		//IL_091e: Expected O, but got Unknown
		//IL_0931: Unknown result type (might be due to invalid IL or missing references)
		//IL_0936: Unknown result type (might be due to invalid IL or missing references)
		//IL_0973: Unknown result type (might be due to invalid IL or missing references)
		//IL_09ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_09f8: Expected O, but got Unknown
		_host = host;
		Teardown();
		try
		{
			ReadStyle(((Component)host).transform);
			Paint.Style = _style;
			Paint.Layer = _style.Layer;
			_root = new GameObject("BMP_Menu")
			{
				layer = _style.Layer
			};
			_root.transform.SetParent(((Component)host).transform, false);
			RectTransform obj = _root.AddComponent<RectTransform>();
			obj.anchorMin = new Vector2(0.5f, 0.5f);
			obj.anchorMax = new Vector2(0.5f, 0.5f);
			obj.pivot = new Vector2(0.5f, 0.5f);
			obj.sizeDelta = new Vector2(980f, 720f);
			obj.anchoredPosition = Vector2.zero;
			_root.transform.localPosition = new Vector3(0f, 0f, -20f);
			_group = _root.AddComponent<CanvasGroup>();
			_openAt = Time.realtimeSinceStartup;
			try
			{
				Canvas componentInParent = ((Component)host).GetComponentInParent<Canvas>();
				if ((Object)componentInParent != (Object)null)
				{
					Log.Info("Overlay shares the game canvas \"" + ((Object)componentInParent).name + "\" (mode " + ((object)componentInParent.renderMode/*cast due to .constrained prefix*/).ToString() + ", camera " + ((Object)componentInParent.worldCamera != (Object)null) + ", layer " + _style.Layer + ").");
				}
				else
				{
					Log.Warn("The menu overlay has no parent canvas (layer " + _style.Layer + ").");
				}
			}
			catch (Exception ex)
			{
				Log.Warn("Reading the parent canvas failed: " + ex.Message);
			}
			Transform transform = _root.transform;
			HudRect panel = MenuLayout.Panel;
			for (int num = 3; num >= 1; num--)
			{
				float num2 = 24f * (float)num / 3f;
				Paint.Pic(transform, "Shadow" + num, new Vector2(panel.X + 7.2f, panel.Y - 12f), new Vector2(panel.W + num2, panel.H + num2), (Texture)(object)Bank.Get("panel"), new Color(0f, 0f, 0f, 0.1f + 0.07f * (float)(3 - num)));
			}
			_backdrop = Paint.Pic(transform, "Backdrop", new HudRect(panel.X, panel.Y, panel.W + 320f, panel.H + 240f), "aurora", new Color(0.1f, 0.2f, 0.4f, 0.85f));
			Paint.Pic(transform, "Panel", panel, "panel", Theme.Panel);
			_glow = Paint.Pic(transform, "Glow", new HudRect(panel.X, panel.Y, panel.W, panel.H), "glow", new Color(0.22f, 0.48f, 1f, 0.55f));
			Paint.Pic(transform, "TitleBar", MenuLayout.TitleBar, "titlebar", Theme.TitleBar);
			Paint.Pic(transform, "Sidebar", MenuLayout.Sidebar, "sidebar", Theme.Sidebar);
			Paint.Solid(transform, "SideDivider", new Vector2(-259f, -27f), new Vector2(1.5f, 600f), Theme.Outline);
			Paint.Frame(transform, "PanelFrame", panel, 18f, Theme.OutlineLine);
			Paint.Solid(transform, "AccentLine", new Vector2(0f, MenuLayout.TitleBar.Bottom), new Vector2(panel.W - 2f, 2f), Theme.A(Theme.Accent, 0.9f));
			Paint.Icon(transform, "TitleIcon", MenuLayout.TitleIcon, "grid", Theme.Accent);
			_title = Paint.Text(transform, "Title", "BONE MENU", MenuLayout.TitleText, 26f, Theme.Text, (TextAlignmentOptions)513, bold: true);
			_title.characterSpacing = 2f;
			_sub = Paint.Text(transform, "SubTitle", "", MenuLayout.SubTitle, 12.5f, Theme.Text2, (TextAlignmentOptions)513);
			Paint.Btn(transform, "Search", MenuLayout.Search, 17f, Theme.Input, Theme