Decompiled source of NorntasticSkillGrowth v0.14.2

plugins\Norntastic.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Norntastic.Auras;
using Norntastic.Brawler;
using Norntastic.Combat;
using Norntastic.Commands;
using Norntastic.Config;
using Norntastic.Content;
using Norntastic.Core;
using Norntastic.Creatures;
using Norntastic.Data;
using Norntastic.Effects;
using Norntastic.Effects.Handlers;
using Norntastic.Emotes;
using Norntastic.Kitchen;
using Norntastic.Martial;
using Norntastic.Progression;
using Norntastic.Safety;
using Norntastic.Styles;
using Norntastic.UI;
using Norntastic.Util;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Norntastic
{
	[BepInPlugin("dafini.norntastic", "Norntastic", "0.14.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "dafini.norntastic";

		public const string PluginName = "Norntastic";

		public const string PluginVersion = "0.14.2";

		private Harmony _harmony;

		private const float PatchMapDelaySeconds = 8f;

		internal static string ConfigDirectory { get; private set; }

		private void Awake()
		{
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			Log.Init(((BaseUnityPlugin)this).Logger);
			ConfigDirectory = Path.Combine(Paths.ConfigPath, "Norntastic");
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			Log.Warn("Built without ServerSync: settings are local only and will not be pushed from the server. Fine for testing, not for the group.");
			PerkPanelInput.Bind(((BaseUnityPlugin)this).Config);
			BrawlerInput.Bind(((BaseUnityPlugin)this).Config);
			OffhandPicker.Bind(((BaseUnityPlugin)this).Config);
			MartialInput.Bind(((BaseUnityPlugin)this).Config);
			AbilityInput.Bind(((BaseUnityPlugin)this).Config);
			PerkDatabase.Load(ConfigDirectory);
			CustomSkills.Register();
			Handlers.RegisterAll();
			BrawlerModifiers.DeclareImplemented();
			PerkEffectDriver.Init();
			EffectAggregator.ReportCoverage();
			DatabaseGuard.Arm();
			Norntastic.Emotes.Emotes.Init(ConfigDirectory);
			DerivedSeal.Load(ConfigDirectory);
			Bakery.Arm();
			PieCounter.Arm();
			Pies.Arm();
			Crops.Arm();
			Arsenal.Arm();
			Pantry.Arm();
			SmokeHook.Arm();
			Fryer.Arm();
			Stations.Arm();
			PerkPanel.Init();
			PerkConsole.Register();
			_harmony = new Harmony("dafini.norntastic");
			_harmony.PatchAll();
			((MonoBehaviour)this).Invoke("WritePatchMap", 8f);
			Log.Info("Norntastic 0.14.2 loaded. " + $"Perk interval {PerkDatabase.PointInterval}, " + "prestige " + (ModConfig.PrestigeEnabled.Value ? "on" : "off") + " " + $"(cap {ModConfig.PrestigeCap.Value}), " + "free respec " + (ModConfig.FreeRespec.Value ? "on" : "off") + ". " + $"Press {PerkPanelInput.Hotkey.Value} for the perk panel.");
		}

		private void WritePatchMap()
		{
			string text = PatchMap.WriteToDisk(ConfigDirectory, "dafini.norntastic");
			if (text != null)
			{
				Log.Info("Patch map written to " + text + ". nsg.patches <text> reads the same thing live.");
			}
		}

		private void OnDestroy()
		{
			PerkPanel.Shutdown();
			PerkEffectDriver.Forget();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace Norntastic.Util
{
	internal static class Equipment
	{
		private struct Snapshot
		{
			internal bool Unarmored;

			internal bool EmptyHanded;

			internal bool Shield;

			internal bool Torch;

			internal bool TwoHanded;

			internal bool OneHanded;

			internal bool MatchedSet;

			internal bool Trinket;
		}

		private const float CacheSeconds = 0.2f;

		private static Snapshot _snap;

		private static float _takenAt = -1f;

		internal static void Invalidate()
		{
			_takenAt = -1f;
		}

		private static Snapshot Current(Player player)
		{
			float time = Time.time;
			if (_takenAt >= 0f && time - _takenAt < 0.2f)
			{
				return _snap;
			}
			_snap = Compute(player);
			_takenAt = time;
			return _snap;
		}

		internal static bool IsUnarmored(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return Current(player).Unarmored;
			}
			return false;
		}

		internal static bool IsEmptyHanded(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return Current(player).EmptyHanded;
			}
			return false;
		}

		internal static bool HasShield(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return Current(player).Shield;
			}
			return false;
		}

		internal static bool HasTorch(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return Current(player).Torch;
			}
			return false;
		}

		internal static bool IsTwoHanded(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return Current(player).TwoHanded;
			}
			return false;
		}

		internal static bool IsOneHanded(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return Current(player).OneHanded;
			}
			return false;
		}

		internal static bool IsFullMatchedSet(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return Current(player).MatchedSet;
			}
			return false;
		}

		internal static bool HasTrinket(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return Current(player).Trinket;
			}
			return false;
		}

		private static bool TrainsUnarmed(ItemData item)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			if (item?.m_shared != null)
			{
				return (int)item.m_shared.m_skillType == 11;
			}
			return false;
		}

		private static Snapshot Compute(Player player)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_00e6: Expected I4, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Invalid comparison between Unknown and I4
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Invalid comparison between Unknown and I4
			Snapshot result = new Snapshot
			{
				Unarmored = true,
				EmptyHanded = true
			};
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return result;
			}
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null)
			{
				return result;
			}
			string helmet = null;
			string chest = null;
			string legs = null;
			foreach (ItemData item in allItems)
			{
				if (item == null || !item.m_equipped || item.m_shared == null)
				{
					continue;
				}
				ItemType itemType = item.m_shared.m_itemType;
				if (IsArmorSlot(itemType))
				{
					result.Unarmored = false;
				}
				if (IsHeldSlot(itemType) && !TrainsUnarmed(item))
				{
					result.EmptyHanded = false;
				}
				switch (itemType - 3)
				{
				default:
					if ((int)itemType != 22)
					{
						if ((int)itemType == 24)
						{
							result.Trinket = true;
						}
						break;
					}
					goto case 1;
				case 2:
					result.Shield = true;
					break;
				case 12:
					result.Torch = true;
					break;
				case 3:
					helmet = item.m_shared.m_name;
					break;
				case 4:
					chest = item.m_shared.m_name;
					break;
				case 8:
					legs = item.m_shared.m_name;
					break;
				case 1:
				case 11:
					result.TwoHanded = true;
					break;
				case 0:
					result.OneHanded = true;
					break;
				case 5:
				case 6:
				case 7:
				case 9:
				case 10:
					break;
				}
			}
			result.MatchedSet = Matched(helmet, chest, legs);
			return result;
		}

		private static bool Matched(string helmet, string chest, string legs)
		{
			if (helmet == null || chest == null || legs == null)
			{
				return false;
			}
			string text = Letters(helmet);
			string text2 = Letters(chest);
			string text3 = Letters(legs);
			if (text.Length < 4 || text2.Length < 4 || text3.Length < 4)
			{
				return false;
			}
			for (int num = Math.Min(text.Length, Math.Min(text2.Length, text3.Length)); num >= 4; num--)
			{
				for (int i = 0; i + num <= text.Length; i++)
				{
					string value = text.Substring(i, num);
					if (text2.IndexOf(value, StringComparison.Ordinal) >= 0 && text3.IndexOf(value, StringComparison.Ordinal) >= 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static string Letters(string raw)
		{
			char[] array = new char[raw.Length];
			int length = 0;
			foreach (char c in raw)
			{
				if (char.IsLetter(c))
				{
					array[length++] = char.ToLowerInvariant(c);
				}
			}
			return new string(array, 0, length);
		}

		private static bool IsHeldSlot(ItemType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Invalid comparison between Unknown and I4
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected I4, but got Unknown
			if (type - 3 > 2)
			{
				switch (type - 14)
				{
				case 0:
				case 1:
				case 5:
				case 6:
				case 8:
					break;
				default:
					return false;
				}
			}
			return true;
		}

		private static bool IsArmorSlot(ItemType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Invalid comparison between Unknown and I4
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			if (type - 6 <= 1 || (int)type == 11 || (int)type == 17)
			{
				return true;
			}
			return false;
		}
	}
	internal static class Json
	{
		internal static object Parse(string text)
		{
			int i = 0;
			object result = ParseValue(text, ref i);
			SkipWhitespace(text, ref i);
			if (i < text.Length)
			{
				throw new FormatException("Trailing content at offset " + i);
			}
			return result;
		}

		internal static Dictionary<string, object> Obj(object o)
		{
			return o as Dictionary<string, object>;
		}

		internal static List<object> Arr(object o)
		{
			return o as List<object>;
		}

		internal static object Get(object o, string key)
		{
			if (!(o is Dictionary<string, object> dictionary))
			{
				return null;
			}
			if (!dictionary.TryGetValue(key, out var value))
			{
				return null;
			}
			return value;
		}

		internal static string Str(object o, string key, string fallback = "")
		{
			return (Get(o, key) as string) ?? fallback;
		}

		internal static float Num(object o, string key, float fallback = 0f)
		{
			if (!(Get(o, key) is double num))
			{
				return fallback;
			}
			return (float)num;
		}

		internal static int Int(object o, string key, int fallback = 0)
		{
			if (!(Get(o, key) is double a))
			{
				return fallback;
			}
			return (int)Math.Round(a);
		}

		internal static bool Bool(object o, string key, bool fallback = false)
		{
			object obj = Get(o, key);
			if (obj is bool)
			{
				return (bool)obj;
			}
			return fallback;
		}

		internal static List<string> StrList(object o, string key)
		{
			List<string> list = new List<string>();
			if (!(Get(o, key) is List<object> list2))
			{
				return list;
			}
			foreach (object item2 in list2)
			{
				if (item2 is string item)
				{
					list.Add(item);
				}
			}
			return list;
		}

		private static void SkipWhitespace(string s, ref int i)
		{
			while (i < s.Length && (s[i] == ' ' || s[i] == '\t' || s[i] == '\n' || s[i] == '\r'))
			{
				i++;
			}
		}

		private static object ParseValue(string s, ref int i)
		{
			SkipWhitespace(s, ref i);
			if (i >= s.Length)
			{
				throw new FormatException("Unexpected end of input");
			}
			switch (s[i])
			{
			case '{':
				return ParseObject(s, ref i);
			case '[':
				return ParseArray(s, ref i);
			case '"':
				return ParseString(s, ref i);
			case 't':
				Expect(s, ref i, "true");
				return true;
			case 'f':
				Expect(s, ref i, "false");
				return false;
			case 'n':
				Expect(s, ref i, "null");
				return null;
			default:
				return ParseNumber(s, ref i);
			}
		}

		private static void Expect(string s, ref int i, string literal)
		{
			if (i + literal.Length > s.Length || string.CompareOrdinal(s, i, literal, 0, literal.Length) != 0)
			{
				throw new FormatException("Expected '" + literal + "' at offset " + i);
			}
			i += literal.Length;
		}

		private static Dictionary<string, object> ParseObject(string s, ref int i)
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			i++;
			SkipWhitespace(s, ref i);
			if (i < s.Length && s[i] == '}')
			{
				i++;
				return dictionary;
			}
			while (true)
			{
				SkipWhitespace(s, ref i);
				if (i >= s.Length || s[i] != '"')
				{
					throw new FormatException("Expected object key at offset " + i);
				}
				string key = ParseString(s, ref i);
				SkipWhitespace(s, ref i);
				if (i >= s.Length || s[i] != ':')
				{
					throw new FormatException("Expected ':' at offset " + i);
				}
				i++;
				dictionary[key] = ParseValue(s, ref i);
				SkipWhitespace(s, ref i);
				if (i >= s.Length)
				{
					throw new FormatException("Unterminated object");
				}
				if (s[i] != ',')
				{
					break;
				}
				i++;
			}
			if (s[i] == '}')
			{
				i++;
				return dictionary;
			}
			throw new FormatException("Expected ',' or '}' at offset " + i);
		}

		private static List<object> ParseArray(string s, ref int i)
		{
			List<object> list = new List<object>();
			i++;
			SkipWhitespace(s, ref i);
			if (i < s.Length && s[i] == ']')
			{
				i++;
				return list;
			}
			while (true)
			{
				list.Add(ParseValue(s, ref i));
				SkipWhitespace(s, ref i);
				if (i >= s.Length)
				{
					throw new FormatException("Unterminated array");
				}
				if (s[i] != ',')
				{
					break;
				}
				i++;
			}
			if (s[i] == ']')
			{
				i++;
				return list;
			}
			throw new FormatException("Expected ',' or ']' at offset " + i);
		}

		private static string ParseString(string s, ref int i)
		{
			StringBuilder stringBuilder = new StringBuilder();
			i++;
			while (i < s.Length)
			{
				char c = s[i++];
				switch (c)
				{
				case '"':
					return stringBuilder.ToString();
				default:
					stringBuilder.Append(c);
					continue;
				case '\\':
					break;
				}
				if (i >= s.Length)
				{
					break;
				}
				char c2 = s[i++];
				switch (c2)
				{
				case '"':
					stringBuilder.Append('"');
					break;
				case '\\':
					stringBuilder.Append('\\');
					break;
				case '/':
					stringBuilder.Append('/');
					break;
				case 'b':
					stringBuilder.Append('\b');
					break;
				case 'f':
					stringBuilder.Append('\f');
					break;
				case 'n':
					stringBuilder.Append('\n');
					break;
				case 'r':
					stringBuilder.Append('\r');
					break;
				case 't':
					stringBuilder.Append('\t');
					break;
				case 'u':
					if (i + 4 > s.Length)
					{
						throw new FormatException("Bad \\u escape");
					}
					stringBuilder.Append((char)Convert.ToInt32(s.Substring(i, 4), 16));
					i += 4;
					break;
				default:
					throw new FormatException("Unknown escape '\\" + c2 + "'");
				}
			}
			throw new FormatException("Unterminated string");
		}

		private static object ParseNumber(string s, ref int i)
		{
			int num = i;
			if (i < s.Length && (s[i] == '-' || s[i] == '+'))
			{
				i++;
			}
			while (i < s.Length && (char.IsDigit(s[i]) || s[i] == '.' || s[i] == 'e' || s[i] == 'E' || s[i] == '+' || s[i] == '-'))
			{
				i++;
			}
			string text = s.Substring(num, i - num);
			if (double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			throw new FormatException("Bad number '" + text + "' at offset " + num);
		}
	}
	internal static class Log
	{
		private static ManualLogSource _log;

		internal static void Init(ManualLogSource source)
		{
			_log = source;
		}

		internal static void Info(string msg)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)msg);
			}
		}

		internal static void Warn(string msg)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogWarning((object)msg);
			}
		}

		internal static void Error(string msg)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogError((object)msg);
			}
		}

		internal static void Debug(string msg)
		{
			if (ModConfig.Verbose != null && ModConfig.Verbose.Value)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)("[dbg] " + msg));
				}
			}
		}
	}
	internal static class PatchMap
	{
		internal sealed class Entry
		{
			internal string Type = "?";

			internal string Method = "?";

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

			internal int Prefixes;

			internal int Postfixes;

			internal int Transpilers;

			internal int Finalizers;

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

			internal string Where => Type + "." + Method;

			internal bool Shared => Owners.Count > 1;

			internal string Counts => $"pre {Prefixes}  post {Postfixes}  trans {Transpilers}  fin {Finalizers}";

			internal bool OwnedBy(string id)
			{
				if (id != null)
				{
					return Owners.Contains(id);
				}
				return false;
			}
		}

		internal const string FileName = "patchmap.txt";

		internal static List<Entry> Collect()
		{
			List<Entry> list = new List<Entry>();
			IEnumerable<MethodBase> allPatchedMethods;
			try
			{
				allPatchedMethods = Harmony.GetAllPatchedMethods();
			}
			catch (Exception ex)
			{
				Log.Warn("Patch map unavailable: " + ex.Message);
				return list;
			}
			if (allPatchedMethods == null)
			{
				return list;
			}
			foreach (MethodBase item in allPatchedMethods)
			{
				if (item == null)
				{
					continue;
				}
				Patches patchInfo;
				try
				{
					patchInfo = Harmony.GetPatchInfo(item);
				}
				catch
				{
					continue;
				}
				if (patchInfo == null)
				{
					continue;
				}
				Entry entry = new Entry
				{
					Type = ((item.DeclaringType != null) ? item.DeclaringType.Name : "?"),
					Method = (item.Name ?? "?")
				};
				if (patchInfo.Owners != null)
				{
					foreach (string owner in patchInfo.Owners)
					{
						if (!string.IsNullOrEmpty(owner) && !entry.Owners.Contains(owner))
						{
							entry.Owners.Add(owner);
						}
					}
				}
				entry.Prefixes = Count(patchInfo.Prefixes);
				entry.Postfixes = Count(patchInfo.Postfixes);
				entry.Transpilers = Count(patchInfo.Transpilers);
				entry.Finalizers = Count(patchInfo.Finalizers);
				AddDetail(patchInfo, entry);
				list.Add(entry);
			}
			list.Sort((Entry a, Entry b) => string.Compare(a.Where, b.Where, StringComparison.Ordinal));
			return list;
		}

		private static int Count<T>(ICollection<T> patches)
		{
			return patches?.Count ?? 0;
		}

		private static void AddDetail(Patches info, Entry entry)
		{
			try
			{
				Describe(info.Prefixes, "prefix", entry);
				Describe(info.Postfixes, "postfix", entry);
				Describe(info.Transpilers, "TRANSPILER", entry);
				Describe(info.Finalizers, "finalizer", entry);
			}
			catch
			{
				entry.Detail.Clear();
			}
		}

		private static void Describe(IEnumerable<Patch> patches, string kind, Entry entry)
		{
			if (patches == null)
			{
				return;
			}
			foreach (Patch patch in patches)
			{
				if (patch != null)
				{
					entry.Detail.Add(patch.owner + " (" + kind + ")");
				}
			}
		}

		internal static List<string> Report(string ourId, string filter)
		{
			List<string> list = new List<string>();
			List<Entry> list2 = Collect();
			if (list2.Count == 0)
			{
				list.Add("No patches visible. Either Harmony has not run yet or it is not the Harmony this mod is talking to.");
				return list;
			}
			string text = (string.IsNullOrEmpty(filter) ? null : filter.ToLowerInvariant());
			List<Entry> list3 = new List<Entry>();
			foreach (Entry item in list2)
			{
				if (text == null || Matches(item, text))
				{
					list3.Add(item);
				}
			}
			int num = 0;
			foreach (Entry item2 in list2)
			{
				if (item2.Shared && item2.OwnedBy(ourId))
				{
					num++;
				}
			}
			list.Add($"--- patch map --- {list2.Count} patched method(s), " + $"{num} of them shared with Norntastic" + ((text == null) ? "" : $"   filter '{filter}' -> {list3.Count}"));
			if (list3.Count == 0)
			{
				list.Add("Nothing matches '" + filter + "'. Nobody has patched it, which for a crash in that method means the cause is somewhere else.");
				return list;
			}
			foreach (Entry item3 in list3)
			{
				string text2 = (item3.Shared ? ">>" : "  ");
				string text3 = (item3.OwnedBy(ourId) ? " [us]" : "");
				list.Add(text2 + " " + item3.Where + text3);
				list.Add("     " + item3.Counts);
				if (item3.Detail.Count > 0)
				{
					foreach (string item4 in item3.Detail)
					{
						list.Add("     " + item4);
					}
					continue;
				}
				foreach (string owner in item3.Owners)
				{
					list.Add("     " + owner);
				}
			}
			return list;
		}

		private static bool Matches(Entry entry, string needle)
		{
			if (entry.Where.ToLowerInvariant().Contains(needle))
			{
				return true;
			}
			foreach (string owner in entry.Owners)
			{
				if (owner != null && owner.ToLowerInvariant().Contains(needle))
				{
					return true;
				}
			}
			return false;
		}

		internal static string WriteToDisk(string directory, string ourId)
		{
			try
			{
				if (string.IsNullOrEmpty(directory))
				{
					return null;
				}
				Directory.CreateDirectory(directory);
				string text = Path.Combine(directory, "patchmap.txt");
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("Norntastic patch map");
				stringBuilder.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("Every method Harmony has patched this session and which mod did it.");
				stringBuilder.AppendLine(">> marks a method more than one mod touches. [us] marks ours.");
				stringBuilder.AppendLine("A crash inside a patched method names neither the mod nor the patch;");
				stringBuilder.AppendLine("this file is how you get from the method in the stack trace to a GUID.");
				stringBuilder.AppendLine();
				foreach (string item in Report(ourId, null))
				{
					stringBuilder.AppendLine(item);
				}
				File.WriteAllText(text, stringBuilder.ToString());
				return text;
			}
			catch (Exception ex)
			{
				Log.Warn("Could not write the patch map: " + ex.Message);
				return null;
			}
		}
	}
	internal static class SkillKeys
	{
		private static readonly Dictionary<SkillType, string> ToKey;

		private static readonly Dictionary<string, SkillType> FromKey;

		private static readonly Dictionary<SkillType, string> Custom;

		static SkillKeys()
		{
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			ToKey = new Dictionary<SkillType, string>
			{
				{
					(SkillType)1,
					"swords"
				},
				{
					(SkillType)2,
					"knives"
				},
				{
					(SkillType)3,
					"clubs"
				},
				{
					(SkillType)4,
					"polearms"
				},
				{
					(SkillType)5,
					"spears"
				},
				{
					(SkillType)6,
					"blocking"
				},
				{
					(SkillType)7,
					"axes"
				},
				{
					(SkillType)8,
					"bows"
				},
				{
					(SkillType)9,
					"elemental"
				},
				{
					(SkillType)10,
					"bloodmagic"
				},
				{
					(SkillType)11,
					"unarmed"
				},
				{
					(SkillType)12,
					"pickaxes"
				},
				{
					(SkillType)13,
					"woodcutting"
				},
				{
					(SkillType)14,
					"crossbows"
				},
				{
					(SkillType)100,
					"jump"
				},
				{
					(SkillType)101,
					"sneak"
				},
				{
					(SkillType)102,
					"run"
				},
				{
					(SkillType)103,
					"swim"
				},
				{
					(SkillType)104,
					"fishing"
				},
				{
					(SkillType)105,
					"cooking"
				},
				{
					(SkillType)106,
					"farming"
				},
				{
					(SkillType)107,
					"crafting"
				},
				{
					(SkillType)108,
					"dodge"
				},
				{
					(SkillType)110,
					"riding"
				}
			};
			FromKey = new Dictionary<string, SkillType>(StringComparer.OrdinalIgnoreCase);
			Custom = new Dictionary<SkillType, string>();
			foreach (KeyValuePair<SkillType, string> item in ToKey)
			{
				FromKey[item.Value] = item.Key;
			}
		}

		internal static bool IsRealSkill(SkillType t)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			if ((int)t != 0)
			{
				return (int)t != 999;
			}
			return false;
		}

		internal static string Key(SkillType t)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected I4, but got Unknown
			if (ToKey.TryGetValue(t, out var value))
			{
				return value;
			}
			if (Custom.TryGetValue(t, out var value2))
			{
				return value2;
			}
			return "skill_" + (int)t;
		}

		internal static bool TryResolve(string key, out SkillType type)
		{
			return FromKey.TryGetValue(key, out type);
		}

		internal static void RegisterCustomKey(SkillType type, string key)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Custom[type] = key;
			FromKey[key] = type;
		}

		internal static void RegisterCustom(SkillType type, string readableName)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (!ToKey.ContainsKey(type))
			{
				string text = "x_" + Sanitise(readableName);
				Custom[type] = text;
				FromKey[text] = type;
			}
		}

		private static string Sanitise(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "unknown";
			}
			StringBuilder stringBuilder = new StringBuilder(s.Length);
			string text = s.Trim().ToLowerInvariant();
			foreach (char c in text)
			{
				if (char.IsLetterOrDigit(c))
				{
					stringBuilder.Append(c);
				}
				else if (c == ' ' || c == '_' || c == '-')
				{
					stringBuilder.Append('_');
				}
			}
			if (stringBuilder.Length != 0)
			{
				return stringBuilder.ToString();
			}
			return "unknown";
		}
	}
}
namespace Norntastic.UI
{
	internal static class Favourites
	{
		private static readonly List<string> Pinned = new List<string>();

		private static bool _loaded;

		internal static IReadOnlyList<string> All
		{
			get
			{
				Load();
				return Pinned;
			}
		}

		internal static int Count
		{
			get
			{
				Load();
				return Pinned.Count;
			}
		}

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

		internal static bool Toggle(string key)
		{
			Load();
			if (string.IsNullOrEmpty(key))
			{
				return false;
			}
			if (Pinned.Contains(key))
			{
				Pinned.Remove(key);
			}
			else
			{
				Pinned.Add(key);
			}
			Save();
			return Pinned.Contains(key);
		}

		private static void Load()
		{
			if (_loaded)
			{
				return;
			}
			_loaded = true;
			Pinned.Clear();
			string text = ModConfig.FavouriteTrees?.Value;
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			string[] array = text.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length > 0 && !Pinned.Contains(text2) && PerkDatabase.Trees.ContainsKey(text2))
				{
					Pinned.Add(text2);
				}
			}
		}

		private static void Save()
		{
			if (ModConfig.FavouriteTrees != null)
			{
				ModConfig.FavouriteTrees.Value = string.Join(",", Pinned.ToArray());
			}
		}

		internal static void ResetForTests()
		{
			Pinned.Clear();
			_loaded = false;
		}
	}
	internal static class Palette
	{
		internal static readonly Color Ground = Color32.op_Implicit(new Color32((byte)11, (byte)14, (byte)18, (byte)242));

		internal static readonly Color Panel = Color32.op_Implicit(new Color32((byte)20, (byte)26, (byte)33, byte.MaxValue));

		internal static readonly Color Panel2 = Color32.op_Implicit(new Color32((byte)27, (byte)35, (byte)44, byte.MaxValue));

		internal static readonly Color Panel3 = Color32.op_Implicit(new Color32((byte)34, (byte)44, (byte)55, byte.MaxValue));

		internal static readonly Color Line = Color32.op_Implicit(new Color32((byte)42, (byte)54, (byte)65, byte.MaxValue));

		internal static readonly Color Ink = Color32.op_Implicit(new Color32((byte)216, (byte)224, (byte)232, byte.MaxValue));

		internal static readonly Color Ink2 = Color32.op_Implicit(new Color32((byte)168, (byte)182, (byte)194, byte.MaxValue));

		internal static readonly Color InkDim = Color32.op_Implicit(new Color32((byte)117, (byte)133, (byte)143, byte.MaxValue));

		internal static readonly Color Ember = Color32.op_Implicit(new Color32((byte)222, (byte)116, (byte)48, byte.MaxValue));

		internal static readonly Color Gold = Color32.op_Implicit(new Color32((byte)233, (byte)180, (byte)95, byte.MaxValue));

		internal static readonly Color Frost = Color32.op_Implicit(new Color32((byte)111, (byte)169, (byte)196, byte.MaxValue));

		internal static readonly Color Blood = Color32.op_Implicit(new Color32((byte)168, (byte)65, (byte)63, byte.MaxValue));

		internal static Color NodeFill(NodeVisualState state)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(state switch
			{
				NodeVisualState.Max => Color32.op_Implicit(new Color32((byte)168, (byte)114, (byte)31, byte.MaxValue)), 
				NodeVisualState.Taken => Color32.op_Implicit(new Color32((byte)200, (byte)98, (byte)31, byte.MaxValue)), 
				NodeVisualState.Held => Color32.op_Implicit(new Color32((byte)200, (byte)98, (byte)31, byte.MaxValue)), 
				NodeVisualState.Available => Panel3, 
				_ => Panel2, 
			});
		}

		internal static Color NodeBorder(NodeVisualState state)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(state switch
			{
				NodeVisualState.Max => Gold, 
				NodeVisualState.Taken => Ember, 
				NodeVisualState.Held => Gold, 
				NodeVisualState.Available => Frost, 
				_ => Line, 
			});
		}

		internal static Color NodeLabel(NodeVisualState state)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			switch (state)
			{
			case NodeVisualState.Taken:
			case NodeVisualState.Max:
			case NodeVisualState.Held:
				return Gold;
			case NodeVisualState.Available:
				return Ink;
			default:
				return new Color(InkDim.r, InkDim.g, InkDim.b, 0.5f);
			}
		}
	}
	internal enum NodeVisualState
	{
		Locked,
		Available,
		Taken,
		Max,
		Held
	}
	internal sealed class PerkDetailPane
	{
		private readonly RectTransform _root;

		private readonly Text _title;

		private readonly Text _meta;

		private readonly Text _flavour;

		private readonly Text _ranks;

		private readonly Text _gate;

		private readonly Button _buy;

		private readonly Text _buyLabel;

		private readonly Button _refund;

		private readonly Text _refundLabel;

		private PerkNode _node;

		internal event Action Changed;

		internal PerkDetailPane(Transform parent)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_00a5: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Expected O, but got Unknown
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b3: Expected O, but got Unknown
			_root = UiFactory.Rect("detail", parent, new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(-330f, 12f), new Vector2(-12f, -12f));
			UiFactory.Fill(_root, Palette.Panel);
			_title = UiFactory.Label("title", (Transform)(object)_root, "", 22, Palette.Ink, (TextAnchor)0, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(16f, -50f), new Vector2(-16f, -14f));
			_meta = UiFactory.Label("meta", (Transform)(object)_root, "", 11, Palette.InkDim, (TextAnchor)0, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(16f, -70f), new Vector2(-16f, -50f));
			_flavour = UiFactory.Label("flavour", (Transform)(object)_root, "", 13, Palette.Ink2, (TextAnchor)0, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(18f, -118f), new Vector2(-16f, -74f));
			_flavour.fontStyle = (FontStyle)2;
			_ranks = UiFactory.Label("ranks", (Transform)(object)_root, "", 13, Palette.Ink2, (TextAnchor)0, new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(16f, 108f), new Vector2(-16f, -122f));
			_gate = UiFactory.Label("gate", (Transform)(object)_root, "", 12, Palette.Blood, (TextAnchor)6, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(16f, 60f), new Vector2(-16f, 104f));
			RectTransform val = UiFactory.Rect("buy", (Transform)(object)_root, new Vector2(0f, 0f), new Vector2(0.62f, 0f), new Vector2(16f, 16f), new Vector2(-4f, 52f));
			_buy = UiFactory.Clickable(val, Color32.op_Implicit(new Color32((byte)90, (byte)46, (byte)20, byte.MaxValue)));
			_buyLabel = UiFactory.Label("t", (Transform)(object)val, "TAKE PERK", 13, Palette.Gold, (TextAnchor)4, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
			((UnityEvent)_buy.onClick).AddListener(new UnityAction(Buy));
			RectTransform val2 = UiFactory.Rect("refund", (Transform)(object)_root, new Vector2(0.62f, 0f), new Vector2(1f, 0f), new Vector2(4f, 16f), new Vector2(-16f, 52f));
			_refund = UiFactory.Clickable(val2, Palette.Panel3);
			_refundLabel = UiFactory.Label("t", (Transform)(object)val2, "REFUND", 13, Palette.InkDim, (TextAnchor)4, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
			((UnityEvent)_refund.onClick).AddListener(new UnityAction(Refund));
		}

		internal void Show(PerkNode node)
		{
			_node = node;
			Refresh();
		}

		private void Buy()
		{
			if (_node != null)
			{
				if (PointMath.TryBuy(PerkState.Current, _node, out var message))
				{
					Toast(message);
				}
				Refresh();
				this.Changed?.Invoke();
			}
		}

		private void Refund()
		{
			if (_node != null)
			{
				if (Respec.TryRefund(PerkState.Current, _node, out var message))
				{
					Toast(message);
				}
				Refresh();
				this.Changed?.Invoke();
			}
		}

		private static void Toast(string message)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)1, message, 0, (Sprite)null, false);
			}
		}

		internal void Refresh()
		{
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_045d: Unknown result type (might be due to invalid IL or missing references)
			if (_node == null)
			{
				_title.text = "";
				_meta.text = "Pick a perk.";
				Text flavour = _flavour;
				Text ranks = _ranks;
				string text = (_gate.text = "");
				string text3 = (ranks.text = text);
				flavour.text = text3;
				Button buy = _buy;
				bool interactable = (((Selectable)_refund).interactable = false);
				((Selectable)buy).interactable = interactable;
				return;
			}
			PerkState current = PerkState.Current;
			PerkTree perkTree = PerkDatabase.Tree(_node.TreeKey);
			int rank = current.GetRank(_node.Id);
			NodeVisualState nodeVisualState = PerkTreeView.Visual(current, _node);
			_title.text = _node.Name;
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append((perkTree != null) ? perkTree.Name : _node.TreeKey);
			stringBuilder.Append("   lv ").Append(_node.RequiresLevel).Append("+");
			stringBuilder.Append("   ").Append(rank).Append(" / ")
				.Append(_node.MaxRank)
				.Append(" ranks");
			if (_node.Requires.Count > 0 && perkTree != null)
			{
				List<string> list = new List<string>();
				foreach (string require in _node.Requires)
				{
					PerkNode perkNode = perkTree.Node(require);
					if (perkNode != null)
					{
						list.Add(perkNode.Name);
					}
				}
				if (list.Count > 0)
				{
					stringBuilder.Append("   after ").Append(string.Join(", ", list.ToArray()));
				}
			}
			_meta.text = stringBuilder.ToString();
			_flavour.text = (string.IsNullOrEmpty(_node.Flavour) ? "" : ("“" + _node.Flavour + "”"));
			StringBuilder stringBuilder2 = new StringBuilder();
			for (int i = 1; i <= _node.MaxRank; i++)
			{
				bool flag2 = i <= rank;
				stringBuilder2.Append(flag2 ? "<color=#DE7430>" : "<color=#75858F>").Append(i).Append("</color>   ")
					.Append(flag2 ? "<color=#D8E0E8>" : "<color=#75858F>")
					.Append(_node.RankText(i))
					.Append("</color>\n\n");
			}
			_ranks.supportRichText = true;
			_ranks.text = stringBuilder2.ToString();
			List<string> list2 = new List<string>();
			if (nodeVisualState == NodeVisualState.Held)
			{
				list2.Add("<color=#E9B45F>Held. Bought above this level and still applying — gates are checked at purchase only.</color>");
			}
			if (_node.IsExclusive)
			{
				PerkNode perkNode2 = PointMath.ExclusiveBlocker(current, perkTree, _node);
				list2.Add((perkNode2 == null) ? "<color=#6FA9C4>An exclusive fork. Taking it locks the others until refunded.</color>" : ("<color=#A8413F>Locked: you committed to " + perkNode2.Name + ".</color>"));
			}
			if (!_node.IsImplemented)
			{
				list2.Add("<color=#A8413F>Not yet implemented: " + _node.PendingNote + "</color>");
			}
			else if (_node.IsPartial)
			{
				list2.Add("<color=#E9B45F>Partly implemented. What is missing: " + _node.PendingNote + "</color>");
			}
			else if (!string.IsNullOrEmpty(_node.ImplementedNote))
			{
				list2.Add("<color=#8FA8B8>" + _node.ImplementedNote + "</color>");
			}
			string reason;
			PointMath.Gate gate = PointMath.CanBuy(current, _node, out reason);
			if (gate != PointMath.Gate.Ok && nodeVisualState != NodeVisualState.Held)
			{
				list2.Add("<color=#E2A3A1>" + reason + "</color>");
			}
			_gate.supportRichText = true;
			_gate.text = string.Join("\n", list2.ToArray());
			((Selectable)_buy).interactable = gate == PointMath.Gate.Ok;
			_buyLabel.text = ((rank > 0) ? "NEXT RANK" : "TAKE PERK");
			((Graphic)_buyLabel).color = (((Selectable)_buy).interactable ? Palette.Gold : Palette.InkDim);
			bool flag3 = ModConfig.FreeRespec != null && ModConfig.FreeRespec.Value;
			((Selectable)_refund).interactable = rank > 0 && (flag3 || current.RespecPoints > 0);
			_refundLabel.text = (flag3 ? "REFUND" : "REFUND · 1 RP");
		}
	}
	internal static class PerkPanel
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Action <0>__Build;

			public static Action <1>__OnAllocationChanged;

			public static UnityAction <2>__Close;

			public static Action<PerkTree> <3>__ShowTree;

			public static UnityAction <4>__DoPrestige;

			public static Action <5>__RefreshAll;
		}

		private static GameObject _root;

		private static RectTransform _rootRect;

		private static SkillRail _rail;

		private static TreeSubRail _subRail;

		private static PerkTreeView _treeView;

		private static PerkDetailPane _detail;

		private static Text _ledger;

		private static Text _treeTitle;

		private static Text _treeBlurb;

		private static Text _treeFormula;

		private static Text _empty;

		private static Button _prestige;

		private static Text _prestigeLabel;

		private static PerkTree _current;

		private static float _sizedForScale;

		private static Vector2 _sizedForScreen;

		private const float HeaderHeight = 70f;

		internal static bool IsOpen
		{
			get
			{
				if ((Object)(object)_root != (Object)null)
				{
					return _root.activeSelf;
				}
				return false;
			}
		}

		internal static void Init()
		{
			GUIManager.OnCustomGUIAvailable += Build;
			PerkEvents.AllocationChanged += OnAllocationChanged;
			Log.Debug("Perk panel subscribed to OnCustomGUIAvailable.");
		}

		internal static void Shutdown()
		{
			GUIManager.OnCustomGUIAvailable -= Build;
			PerkEvents.AllocationChanged -= OnAllocationChanged;
			Destroy();
		}

		private static void Destroy()
		{
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			_root = null;
			_rootRect = null;
			_rail = null;
			_subRail = null;
			_treeView = null;
			_detail = null;
			_current = null;
		}

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

		internal static void Open()
		{
			if ((Object)(object)_root == (Object)null)
			{
				Build();
			}
			if ((Object)(object)_root == (Object)null)
			{
				Log.Warn("Perk panel could not be built - custom GUI is not available yet.");
				return;
			}
			_root.SetActive(true);
			GUIManager.BlockInput(true);
			ApplyScale();
			_rail.Build();
			if (_current == null || !_rail.TrySelect(_current.Key))
			{
				_current = null;
				_rail.SelectFirst();
			}
			((Behaviour)_empty).enabled = _rail.IsEmpty;
			RefreshAll();
		}

		internal static void Close()
		{
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(false);
			}
			GUIManager.BlockInput(false);
		}

		private static void ApplyScale()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_rootRect == (Object)null))
			{
				float num = Mathf.Clamp(ModConfig.UiScale.Value, 0.8f, 2.5f);
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor((float)Screen.width, (float)Screen.height);
				((Transform)_rootRect).localScale = new Vector3(num, num, 1f);
				_rootRect.sizeDelta = val / num;
				_sizedForScale = num;
				_sizedForScreen = val;
			}
		}

		private static void Build()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: 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_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Expected O, but got Unknown
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: 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_040d: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			//IL_042b: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0457: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_0476: Unknown result type (might be due to invalid IL or missing references)
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			//IL_0494: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04df: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_050e: Unknown result type (might be due to invalid IL or missing references)
			//IL_051d: Unknown result type (might be due to invalid IL or missing references)
			//IL_052c: Unknown result type (might be due to invalid IL or missing references)
			//IL_053b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0554: Unknown result type (might be due to invalid IL or missing references)
			//IL_0559: Unknown result type (might be due to invalid IL or missing references)
			//IL_0576: Unknown result type (might be due to invalid IL or missing references)
			//IL_057c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0581: Unknown result type (might be due to invalid IL or missing references)
			//IL_0586: Unknown result type (might be due to invalid IL or missing references)
			//IL_058b: 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_05df: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bf: Expected O, but got Unknown
			//IL_063d: Unknown result type (might be due to invalid IL or missing references)
			//IL_064d: Unknown result type (might be due to invalid IL or missing references)
			//IL_065c: Unknown result type (might be due to invalid IL or missing references)
			//IL_066b: Unknown result type (might be due to invalid IL or missing references)
			//IL_067a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)GUIManager.CustomGUIFront == (Object)null))
			{
				Destroy();
				Transform transform = GUIManager.CustomGUIFront.transform;
				_rootRect = UiFactory.Point("NorntasticPanel", transform, new Vector2(0.5f, 0.5f), new Vector2(1920f, 1080f));
				_root = ((Component)_rootRect).gameObject;
				((Graphic)UiFactory.Fill(_rootRect, Palette.Ground)).raycastTarget = true;
				RectTransform parent = UiFactory.Rect("header", (Transform)(object)_rootRect, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(16f, -70f), new Vector2(-16f, 0f));
				UiFactory.Label("brand", (Transform)(object)parent, "NORNTASTIC SKILL GROWTH", 26, Palette.Ember, (TextAnchor)3, new Vector2(0f, 0f), new Vector2(0.38f, 1f), new Vector2(6f, 0f), Vector2.zero);
				_ledger = UiFactory.Label("ledger", (Transform)(object)parent, "", 15, Palette.Ink, (TextAnchor)5, new Vector2(0.38f, 0f), new Vector2(1f, 1f), Vector2.zero, new Vector2(-104f, 0f));
				RectTransform val = UiFactory.Rect("close", (Transform)(object)parent, new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(-92f, 14f), new Vector2(-6f, -14f));
				Button obj = UiFactory.Clickable(val, Palette.Panel3);
				UiFactory.Label("t", (Transform)(object)val, "CLOSE", 14, Palette.Ink2, (TextAnchor)4, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
				ButtonClickedEvent onClick = obj.onClick;
				object obj2 = <>O.<2>__Close;
				if (obj2 == null)
				{
					UnityAction val2 = Close;
					<>O.<2>__Close = val2;
					obj2 = (object)val2;
				}
				((UnityEvent)onClick).AddListener((UnityAction)obj2);
				_rail = new SkillRail((Transform)(object)UiFactory.Rect("railhost", (Transform)(object)_rootRect, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0f, -128f), new Vector2(0f, -70f)));
				_rail.TreeSelected += ShowTree;
				_subRail = new TreeSubRail((Transform)(object)UiFactory.Rect("subrailhost", (Transform)(object)_rootRect, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0f, -162f), new Vector2(0f, -128f)));
				_subRail.TreeSelected += ShowTree;
				RectTransform parent2 = UiFactory.Rect("body", (Transform)(object)_rootRect, Vector2.zero, Vector2.one, new Vector2(0f, 0f), new Vector2(0f, -162f));
				_empty = UiFactory.Label("empty", (Transform)(object)parent2, "No skill has been levelled yet.\nSwing something, and its tree appears here.", 18, Palette.InkDim, (TextAnchor)4, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
				((Behaviour)_empty).enabled = false;
				RectTransform parent3 = UiFactory.Rect("stage", (Transform)(object)parent2, Vector2.zero, Vector2.one, new Vector2(14f, 12f), new Vector2(-394f, -12f));
				RectTransform val3 = UiFactory.Rect("stagehead", (Transform)(object)parent3, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0f, -116f), new Vector2(0f, 0f));
				UiFactory.Fill(val3, Palette.Panel);
				_treeTitle = UiFactory.Label("title", (Transform)(object)val3, "", 26, Palette.Ink, (TextAnchor)0, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(18f, -46f), new Vector2(-176f, -10f));
				_treeBlurb = UiFactory.Label("blurb", (Transform)(object)val3, "", 14, Palette.Ink2, (TextAnchor)0, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(18f, -92f), new Vector2(-176f, -48f));
				_treeFormula = UiFactory.Label("formula", (Transform)(object)val3, "", 12, Palette.InkDim, (TextAnchor)6, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(18f, 6f), new Vector2(-18f, 26f));
				RectTransform val4 = UiFactory.Rect("prestige", (Transform)(object)val3, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-166f, -48f), new Vector2(-14f, -14f));
				_prestige = UiFactory.Clickable(val4, Color32.op_Implicit(new Color32((byte)70, (byte)28, (byte)27, byte.MaxValue)));
				_prestigeLabel = UiFactory.Label("t", (Transform)(object)val4, "PRESTIGE", 13, Palette.Blood, (TextAnchor)4, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
				ButtonClickedEvent onClick2 = _prestige.onClick;
				object obj3 = <>O.<4>__DoPrestige;
				if (obj3 == null)
				{
					UnityAction val5 = DoPrestige;
					<>O.<4>__DoPrestige = val5;
					obj3 = (object)val5;
				}
				((UnityEvent)onClick2).AddListener((UnityAction)obj3);
				RectTransform parent4 = UiFactory.Rect("graph", (Transform)(object)parent3, Vector2.zero, Vector2.one, new Vector2(0f, 0f), new Vector2(0f, -120f));
				_treeView = new PerkTreeView((Transform)(object)parent4);
				_treeView.NodeSelected += delegate(PerkNode node)
				{
					_detail.Show(node);
				};
				UiFactory.Label("hint", (Transform)(object)parent4, "drag to pan  ·  wheel to zoom  ·  click a connector to travel  ·  right-click a tab to pin it", 12, Palette.InkDim, (TextAnchor)6, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(22f, 18f), new Vector2(-22f, 38f));
				_detail = new PerkDetailPane((Transform)(object)parent2);
				_detail.Changed += RefreshAll;
				ApplyScale();
				_root.SetActive(false);
				Log.Debug("Perk panel built.");
			}
		}

		internal static void Tick()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOpen || (Object)(object)_rootRect == (Object)null)
			{
				return;
			}
			if (!Mathf.Approximately(_sizedForScale, ModConfig.UiScale.Value) || _sizedForScreen.x != (float)Screen.width || _sizedForScreen.y != (float)Screen.height)
			{
				ApplyScale();
			}
			Vector2 val = Vector2.op_Implicit(Input.mousePosition);
			float axis = Input.GetAxis("Mouse ScrollWheel");
			if (_rail != null && _rail.ContainsScreenPoint(val))
			{
				if (!Mathf.Approximately(axis, 0f))
				{
					_rail.Wheel(axis);
				}
				_treeView?.Tick(val, pointerOverViewport: false, 0f, _sizedForScale);
			}
			else
			{
				_treeView?.Tick(val, _treeView.ContainsScreenPoint(val), axis, _sizedForScale);
			}
		}

		private static void ShowTree(PerkTree tree)
		{
			_current = tree;
			_subRail?.Show(tree);
			_rail?.Refresh();
			_treeView.Show(tree);
			_detail.Show(tree?.Node(_treeView.Selected));
			RefreshAll();
		}

		private static void DoPrestige()
		{
			if (_current == null)
			{
				return;
			}
			if (Prestige.TryPrestige(PerkState.Current, _current, out var message))
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false);
				}
				_treeView.Show(_current);
			}
			RefreshAll();
		}

		private static void OnAllocationChanged()
		{
			if (IsOpen)
			{
				RefreshAll();
			}
		}

		internal static void RefreshAll()
		{
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_root == (Object)null) && _current != null)
			{
				PerkState current = PerkState.Current;
				int num = PointMath.Earned(current);
				int num2 = PointMath.Spent(current);
				int num3 = PointMath.SpentIn(current, _current);
				_ledger.text = $"{num} earned    {num2} spent    " + $"<color=#E9B45F>{num - num2} to spend anywhere</color>    " + $"<color=#6FA9C4>{current.RespecPoints} RP</color>" + ((num3 > 0) ? $"     <color=#75858F>{num3} in {_current.Name}</color>" : "");
				_ledger.supportRichText = true;
				int prestige = current.GetPrestige(_current.Key);
				_treeTitle.text = ((prestige > 0) ? (_current.Name + "  ✦" + prestige) : _current.Name);
				_treeBlurb.text = _current.Blurb;
				float num4 = PointMath.LevelFor(current, _current);
				if (_current.IsSector)
				{
					_treeFormula.text = $"average member level {num4:0}  →  {num} points   " + $"({_current.Members.Count} members)";
				}
				else if (_current.IsForeign)
				{
					bool flag = ForeignSkills.IsPresent(_current.Key);
					_treeFormula.text = (flag ? ($"from the {_current.ForeignSkill} mod  ·  high-water {num4:0} " + $"/ interval {PerkDatabase.PointInterval}") : ("needs the " + _current.ForeignSkill + " mod, which is not installed"));
				}
				else if (_current.RidesAnotherSkill)
				{
					PerkTree perkTree = PerkDatabase.Tree(_current.RidesKey);
					_treeFormula.text = "follows " + ((perkTree != null) ? perkTree.Name : _current.RidesKey) + " " + $"at level {num4:0}  ·  earns no points of its own";
				}
				else
				{
					_treeFormula.text = $"high-water {num4:0} / interval {PerkDatabase.PointInterval}" + $"  →  {num} points";
				}
				string reason;
				bool flag2 = Prestige.CanPrestige(current, _current, out reason);
				((Selectable)_prestige).interactable = flag2;
				_prestigeLabel.text = ((_current.IsSector || _current.RidesAnotherSkill) ? "INHERITED" : $"PRESTIGE ✦{prestige}/{ModConfig.PrestigeCap.Value}");
				((Graphic)_prestigeLabel).color = (flag2 ? Palette.Gold : Palette.InkDim);
				_rail.Refresh();
				_subRail?.Refresh();
				_treeView.Refresh();
				_detail.Refresh();
			}
		}
	}
	internal static class PerkPanelInput
	{
		internal static ConfigEntry<KeyboardShortcut> Hotkey;

		internal static void Bind(ConfigFile config)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Hotkey = config.Bind<KeyboardShortcut>("UI", "Hotkey", new KeyboardShortcut((KeyCode)112, Array.Empty<KeyCode>()), "Opens the perk panel.");
		}

		internal static void Tick(Player __instance)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (Hotkey == null)
			{
				return;
			}
			if (PerkPanel.IsOpen && Input.GetKeyDown((KeyCode)27))
			{
				PerkPanel.Close();
				return;
			}
			PerkPanel.Tick();
			if (Console.IsVisible() || TextInput.IsVisible())
			{
				return;
			}
			Chat instance = Chat.instance;
			if (instance == null || !instance.HasFocus())
			{
				KeyboardShortcut value = Hotkey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					PerkPanel.Toggle();
				}
			}
		}
	}
	internal sealed class PerkTreeView
	{
		private sealed class NodeWidget
		{
			internal PerkNode Node;

			internal RectTransform Holder;

			internal Image Border;

			internal Image Fill;

			internal Text Rank;

			internal Text Label;

			internal Text Req;

			internal Button Button;
		}

		private readonly RectTransform _root;

		private readonly RectTransform _viewport;

		private readonly RectTransform _world;

		private readonly RectTransform _edges;

		private readonly RectTransform _nodes;

		private readonly CanvasGroup _worldGroup;

		private readonly Dictionary<string, NodeWidget> _widgets = new Dictionary<string, NodeWidget>();

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

		private PerkTree _tree;

		private string _selected;

		private float _zoom = 1f;

		private Vector2 _pan;

		private Vector2 _panTarget;

		private bool _dragging;

		private bool _dragArmed;

		private Vector2 _dragOrigin;

		private Vector2 _panAtDragStart;

		private const float NodeSize = 54f;

		private const float LabelWidth = 168f;

		private const float SpreadX = 2600f;

		private const float SpreadY = 1700f;

		private const float MinZoom = 0.45f;

		private const float MaxZoom = 2.5f;

		private const float EdgeHitThickness = 26f;

		internal string Selected => _selected;

		internal event Action<PerkNode> NodeSelected;

		internal PerkTreeView(Transform parent)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			_root = UiFactory.Rect("tree", parent, Vector2.zero, Vector2.one, new Vector2(12f, 12f), new Vector2(-12f, -12f));
			UiFactory.Fill(_root, Palette.Panel);
			_viewport = UiFactory.Rect("viewport", (Transform)(object)_root, Vector2.zero, Vector2.one, new Vector2(2f, 2f), new Vector2(-2f, -2f));
			((Component)_viewport).gameObject.AddComponent<RectMask2D>();
			_world = UiFactory.Point("world", (Transform)(object)_viewport, new Vector2(0.5f, 0.5f), new Vector2(5200f, 3400f));
			_worldGroup = ((Component)_world).gameObject.AddComponent<CanvasGroup>();
			_edges = UiFactory.Rect("edges", (Transform)(object)_world, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
			_nodes = UiFactory.Rect("nodes", (Transform)(object)_world, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
		}

		internal void Show(PerkTree tree)
		{
			_tree = tree;
			_zoom = Mathf.Clamp(ModConfig.TreeZoom.Value, 0.45f, 2.5f);
			Build();
			string text = null;
			if (tree != null && _focusByTree.TryGetValue(tree.Key, out var value) && tree.Node(value) != null)
			{
				text = value;
			}
			text = text ?? DefaultFocus(tree);
			SetFocus(text, animate: false);
		}

		private static string DefaultFocus(PerkTree tree)
		{
			if (tree == null || tree.Nodes.Count == 0)
			{
				return null;
			}
			PerkState current = PerkState.Current;
			PerkNode perkNode = null;
			foreach (PerkNode node in tree.Nodes)
			{
				if (current.GetRank(node.Id) > 0 && (perkNode == null || node.Y > perkNode.Y))
				{
					perkNode = node;
				}
			}
			return (perkNode ?? tree.Nodes[0]).Id;
		}

		private static Vector2 Place(PerkNode node)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2((node.X / 100f - 0.5f) * 2600f, (0.5f - node.Y / 100f) * 1700f);
		}

		private void Build()
		{
			UiFactory.Clear((Transform)(object)_edges);
			UiFactory.Clear((Transform)(object)_nodes);
			_widgets.Clear();
			if (_tree == null)
			{
				return;
			}
			foreach (PerkNode node in _tree.Nodes)
			{
				_widgets[node.Id] = BuildNode(node);
			}
			Refresh();
		}

		private NodeWidget BuildNode(PerkNode node)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: 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_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = UiFactory.Point("node_" + node.Id, (Transform)(object)_nodes, new Vector2(0.5f, 0.5f), new Vector2(168f, 106f));
			val.anchoredPosition = Place(node);
			RectTransform val2 = UiFactory.Point("gem", (Transform)(object)val, new Vector2(0.5f, 1f), new Vector2(54f, 54f));
			val2.anchoredPosition = new Vector2(0f, -27f);
			Image border = UiFactory.Fill(val2, Palette.Line);
			Image fill = UiFactory.Fill(UiFactory.Rect("fill", (Transform)(object)val2, Vector2.zero, Vector2.one, new Vector2(2f, 2f), new Vector2(-2f, -2f)), Palette.Panel2);
			Button val3 = UiFactory.Clickable(val2, Palette.Line);
			PerkNode captured = node;
			((UnityEvent)val3.onClick).AddListener((UnityAction)delegate
			{
				Select(captured);
			});
			Text rank = UiFactory.Label("rank", (Transform)(object)val2, "", 15, Palette.InkDim, (TextAnchor)4, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
			RectTransform val4 = UiFactory.Rect("plate", (Transform)(object)val, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(14f, 22f), new Vector2(-14f, 44f));
			UiFactory.Fill(val4, Palette.Panel);
			Text val5 = UiFactory.Label("label", (Transform)(object)val4, node.Name, 15, Palette.InkDim, (TextAnchor)4, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
			val5.horizontalOverflow = (HorizontalWrapMode)1;
			RectTransform val6 = UiFactory.Rect("reqplate", (Transform)(object)val, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(24f, 4f), new Vector2(-24f, 20f));
			UiFactory.Fill(val6, Palette.Panel);
			Text val7 = UiFactory.Label("req", (Transform)(object)val6, "lv " + node.RequiresLevel, 12, Palette.InkDim, (TextAnchor)4, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
			val7.horizontalOverflow = (HorizontalWrapMode)1;
			return new NodeWidget
			{
				Node = node,
				Holder = val,
				Border = border,
				Fill = fill,
				Rank = rank,
				Label = val5,
				Req = val7,
				Button = val3
			};
		}

		private void Select(PerkNode node)
		{
			SetFocus(node.Id, animate: true);
			this.NodeSelected?.Invoke(node);
		}

		internal void SetFocus(string nodeId, bool animate)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			_selected = nodeId;
			if (_tree != null && nodeId != null)
			{
				_focusByTree[_tree.Key] = nodeId;
			}
			PerkNode perkNode = _tree?.Node(nodeId);
			if (perkNode != null)
			{
				_panTarget = -Place(perkNode) * _zoom;
				if (!animate)
				{
					_pan = _panTarget;
				}
			}
			ApplyTransform();
			Refresh();
		}

		private void Travel(string fromId, string toId)
		{
			string text = ((_selected == toId) ? fromId : toId);
			PerkNode perkNode = _tree?.Node(text);
			if (perkNode != null)
			{
				SetFocus(text, animate: true);
				this.NodeSelected?.Invoke(perkNode);
			}
		}

		private void ApplyTransform()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			((Transform)_world).localScale = new Vector3(_zoom, _zoom, 1f);
			_world.anchoredPosition = _pan;
		}

		internal void Tick(Vector2 mouse, bool pointerOverViewport, float wheel, float uiScale)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			if (_tree == null)
			{
				return;
			}
			Vector2 val = _pan - _panTarget;
			if (((Vector2)(ref val)).sqrMagnitude > 0.5f && !_dragging)
			{
				float num = 1f - Mathf.Exp(-14f * Time.unscaledDeltaTime);
				_pan = Vector2.Lerp(_pan, _panTarget, num);
				ApplyTransform();
			}
			if (!pointerOverViewport && !_dragging)
			{
				_dragArmed = false;
				return;
			}
			if (!Mathf.Approximately(wheel, 0f))
			{
				float zoom = _zoom;
				_zoom = Mathf.Clamp(_zoom * (1f + wheel * 0.18f), 0.45f, 2.5f);
				if (!Mathf.Approximately(zoom, _zoom))
				{
					float num2 = _zoom / zoom;
					_pan *= num2;
					_panTarget *= num2;
					ApplyTransform();
				}
			}
			if (Input.GetMouseButtonDown(0))
			{
				_dragArmed = true;
				_dragOrigin = mouse;
				_panAtDragStart = _pan;
			}
			if (_dragArmed && Input.GetMouseButton(0))
			{
				Vector2 val2 = (mouse - _dragOrigin) / Mathf.Max(0.01f, uiScale);
				if (!_dragging && ((Vector2)(ref val2)).sqrMagnitude > 30f)
				{
					_dragging = true;
					_worldGroup.blocksRaycasts = false;
				}
				if (_dragging)
				{
					_pan = _panAtDragStart + val2;
					_panTarget = _pan;
					ApplyTransform();
				}
			}
			if (Input.GetMouseButtonUp(0))
			{
				_dragArmed = false;
				if (_dragging)
				{
					_dragging = false;
					_worldGroup.blocksRaycasts = true;
				}
			}
		}

		internal bool ContainsScreenPoint(Vector2 screen)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return UiFactory.ContainsScreenPoint(_viewport, screen);
		}

		internal void Refresh()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Expected O, but got Unknown
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			if (_tree == null)
			{
				return;
			}
			PerkState current = PerkState.Current;
			foreach (NodeWidget value in _widgets.Values)
			{
				PerkNode node = value.Node;
				NodeVisualState nodeVisualState = Visual(current, node);
				((Graphic)value.Border).color = Palette.NodeBorder(nodeVisualState);
				((Graphic)value.Fill).color = Palette.NodeFill(nodeVisualState);
				((Graphic)value.Label).color = Palette.NodeLabel(nodeVisualState);
				value.Rank.text = current.GetRank(node.Id) + "/" + node.MaxRank;
				((Graphic)value.Rank).color = (Color)(nodeVisualState switch
				{
					NodeVisualState.Available => Palette.Frost, 
					NodeVisualState.Locked => Palette.InkDim, 
					_ => Color32.op_Implicit(new Color32((byte)21, (byte)11, (byte)5, byte.MaxValue)), 
				});
				if (!node.IsImplemented)
				{
					value.Req.text = "lv " + node.RequiresLevel + "  ·  pending";
					((Graphic)value.Req).color = Palette.Blood;
				}
				else if (node.IsPartial)
				{
					value.Req.text = "lv " + node.RequiresLevel + "  ·  partial";
					((Graphic)value.Req).color = Palette.Gold;
				}
				else
				{
					value.Req.text = "lv " + node.RequiresLevel;
					((Graphic)value.Req).color = Palette.InkDim;
				}
				((Transform)((Graphic)value.Border).rectTransform).localScale = (Vector3)((node.Id == _selected) ? new Vector3(1.18f, 1.18f, 1f) : Vector3.one);
			}
			UiFactory.Clear((Transform)(object)_edges);
			foreach (PerkNode node2 in _tree.Nodes)
			{
				foreach (string require in node2.Requires)
				{
					PerkNode perkNode = _tree.Node(require);
					if (perkNode != null)
					{
						int rank = current.GetRank(require);
						int rank2 = current.GetRank(node2.Id);
						Color colour = ((rank > 0 && rank2 > 0) ? Palette.Ember : ((rank > 0) ? Palette.Frost : Palette.Line));
						Vector2 val = Place(perkNode);
						Vector2 to = Place(node2);
						string from = require;
						string to2 = node2.Id;
						((UnityEvent)UiFactory.HitLine((Transform)(object)_edges, val, to, 26f).onClick).AddListener((UnityAction)delegate
						{
							Travel(from, to2);
						});
						UiFactory.Connector((Transform)(object)_edges, val, to, (rank > 0 && rank2 > 0) ? 4f : 2.5f, colour);
					}
				}
			}
		}

		internal static NodeVisualState Visual(PerkState state, PerkNode node)
		{
			int rank = state.GetRank(node.Id);
			PerkTree perkTree = PerkDatabase.Tree(node.TreeKey);
			float num = ((perkTree != null) ? PointMath.LevelFor(state, perkTree) : 0f);
			if (rank > 0 && num < (float)node.RequiresLevel)
			{
				return NodeVisualState.Held;
			}
			if (rank >= node.MaxRank && rank > 0)
			{
				return NodeVisualState.Max;
			}
			if (rank > 0)
			{
				return NodeVisualState.Taken;
			}
			if (PointMath.CanBuy(state, node, out var _) != PointMath.Gate.Ok)
			{
				return NodeVisualState.Locked;
			}
			return NodeVisualState.Available;
		}
	}
	internal sealed class RightClick : MonoBehaviour, IPointerClickHandler, IEventSystemHandler
	{
		internal Action Clicked;

		public void OnPointerClick(PointerEventData eventData)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			if (eventData != null && (int)eventData.button == 1)
			{
				Clicked?.Invoke();
			}
		}

		internal static RightClick On(GameObject host, Action action)
		{
			RightClick rightClick = host.AddComponent<RightClick>();
			rightClick.Clicked = action;
			return rightClick;
		}
	}
	internal sealed class SkillRail
	{
		private sealed class Row
		{
			internal bool IsPinnedCopy;

			internal PerkTree Tree;

			internal RectTransform Root;

			internal Image Background;

			internal Image Accent;

			internal Text Name;

			internal Text Tally;
		}

		private readonly RectTransform _root;

		private readonly RectTransform _viewport;

		private readonly RectTransform _content;

		private readonly ScrollRect _scroll;

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

		private string _selected;

		internal const float RailHeight = 58f;

		private const float TabPadding = 18f;

		private const float GroupGap = 26f;

		private const float FadeWidth = 54f;

		private const int NameSize = 17;

		internal bool IsEmpty => _rows.Count == 0;

		internal event Action<PerkTree> TreeSelected;

		internal SkillRail(Transform parent)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_008a: 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_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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			_root = UiFactory.Rect("rail", parent, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0f, -58f), new Vector2(0f, 0f));
			UiFactory.Fill(_root, Palette.Panel);
			_viewport = UiFactory.Rect("viewport", (Transform)(object)_root, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
			((Component)_viewport).gameObject.AddComponent<RectMask2D>();
			_content = UiFactory.Rect("content", (Transform)(object)_viewport, new Vector2(0f, 0f), new Vector2(0f, 1f), Vector2.zero, Vector2.zero);
			_content.pivot = new Vector2(0f, 0.5f);
			((Graphic)UiFactory.Fill(_viewport, new Color(0f, 0f, 0f, 0f))).raycastTarget = true;
			_scroll = ((Component)_root).gameObject.AddComponent<ScrollRect>();
			_scroll.content = _content;
			_scroll.viewport = _viewport;
			_scroll.horizontal = true;
			_scroll.vertical = false;
			_scroll.movementType = (MovementType)2;
			_scroll.scrollSensitivity = 42f;
			_scroll.inertia = true;
			_scroll.decelerationRate = ModConfig.RailGlide?.Value ?? 0.16f;
			UiFactory.EdgeFade(UiFactory.Rect("fade_l", (Transform)(object)_root, new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(54f, 0f)), Palette.Ground, opaqueAtLeft: true);
			UiFactory.EdgeFade(UiFactory.Rect("fade_r", (Transform)(object)_root, new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(-54f, 0f), new Vector2(0f, 0f)), Palette.Ground, opaqueAtLeft: false);
		}

		private static TreeKind GroupOf(PerkTree tree)
		{
			if (!tree.IsForeign)
			{
				return tree.Kind;
			}
			return TreeKind.Stub;
		}

		internal static bool Visible(PerkTree tree, PerkState state)
		{
			if (tree.IsForeign && !ForeignSkills.IsPresent(tree.Key))
			{
				return false;
			}
			if (!ModConfig.HideUnlearnedSkills.Value)
			{
				return true;
			}
			if (tree.AlwaysShown)
			{
				return true;
			}
			foreach (PerkNode node in tree.Nodes)
			{
				if (state.GetRank(node.Id) > 0)
				{
					return true;
				}
			}
			if (tree.IsSector)
			{
				foreach (string member in tree.Members)
				{
					if (state.GetHighWater(member) > 0f)
					{
						return true;
					}
				}
				return false;
			}
			foreach (string item in tree.RevealWith)
			{
				if (state.GetHighWater(item) > 0f)
				{
					return true;
				}
			}
			if (tree.RidesAnotherSkill)
			{
				return state.GetHighWater(tree.RidesKey) > 0f;
			}
			return state.GetHighWater(tree.Key) > 0f;
		}

		internal void Build()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			UiFactory.Clear((Transform)(object)_content);
			_rows.Clear();
			PerkState current = PerkState.Current;
			float x = 27f;
			x = Pinned(current, x);
			x = Group("SKILLS", TreeKind.Skill, current, x);
			x = Group("NEW", TreeKind.New, current, x);
			x = Group("SECTORS", TreeKind.Sector, current, x);
			x = Group("MODDED", TreeKind.Stub, current, x);
			_content.sizeDelta = new Vector2(x + 27f, 0f);
			Refresh();
		}

		private float Pinned(PerkState state, float x)
		{
			List<string> list = new List<string>();
			foreach (string item in Favourites.All)
			{
				if (PerkDatabase.Trees.TryGetValue(item, out var value) && Visible(value, state))
				{
					list.Add(item);
				}
			}
			if (list.Count == 0)
			{
				return x;
			}
			x = Tag("PINNED", x);
			foreach (string item2 in list)
			{
				PerkTree tree = PerkDatabase.Trees[item2];
				float num = TabWidth(tree);
				_rows.Add(BuildTab(tree, x, num, pinnedCopy: true));
				x += num;
			}
			return x + 26f;
		}

		private float Tag(string title, float x)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			RectTransform parent = UiFactory.Rect("g_" + title, (Transform)(object)_content, new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(x, 6f), new Vector2(x + 16f, -6f));
			Text obj = UiFactory.Label("t", (Transform)(object)parent, title, 10, Palette.InkDim, (TextAnchor)4, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, Vector2.zero);
			((Graphic)obj).rectTransform.sizeDelta = new Vector2(44f, 16f);
			((Graphic)obj).rectTransform.anchoredPosition = Vector2.zero;
			obj.horizontalOverflow = (HorizontalWrapMode)1;
			((Transform)((Graphic)obj).rectTransform).localRotation = Quaternion.Euler(0f, 0f, 90f);
			return x + 16f + 10f;
		}

		private float Group(string title, TreeKind kind, PerkState state, float x)
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, PerkTree> tree2 in PerkDatabase.Trees)
			{
				if (GroupOf(tree2.Value) == kind && Visible(tree2.Value, state))
				{
					list.Add(tree2.Key);
				}
			}
			if (list.Count == 0)
			{
				return x;
			}
			if (x > 54f)
			{
				x += 26f;
			}
			x = Tag(title, x);
			foreach (string item in list)
			{
				PerkTree tree = PerkDatabase.Trees[item];
				float num = TabWidth(tree);
				_rows.Add(BuildTab(tree, x, num, pinnedCopy: false));
				x += num;
			}
			return x;
		}

		private static float TabWidth(PerkTree tree)
		{
			return Mathf.Max(84f, (float)tree.Name.Length * 9.2f + 36f);
		}

		private Row BuildTab(PerkTree tree, float x, float width, bool pinnedCopy)
		{
			//IL_0039: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: 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_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: 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)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: 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_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			RectTransform rt = UiFactory.Rect((pinnedCopy ? "pin_" : "tab_") + tree.Key, (Transform)(object)_content, new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(x, 4f), new Vector2(x + width, -4f));
			Button obj = UiFactory.Clickable(rt, new Color(0f, 0f, 0f, 0f));
			PerkTree captured = tree;
			((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
			{
				Select(captured, rt);
			});
			RightClick.On(((Component)rt).gameObject, delegate
			{
				Favourites.Toggle(captured.Key);
				Build();
				TrySelect(_selected);
			});
			Text val = UiFactory.Label("name", (Transform)(object)rt, tree.Name, 17, Palette.Ink2, (TextAnchor)4, Vector2.zero, Vector2.one, new Vector2(6f, 0f), new Vector2(-6f, 4f));
			val.horizontalOverflow = (HorizontalWrapMode)1;
			Image accent = UiFactory.Fill(UiFactory.Rect("accent", (Transform)(object)rt, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(9f, 0f), new Vector2(-9f, 3f)), new Color(0f, 0f, 0f, 0f));
			Text tally = UiFactory.Label("tally", (Transform)(object)rt, "", 11, Palette.Gold, (TextAnchor)2, new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(0f, 0f), new Vector2(-5f, -4f));
			return new Row
			{
				Tree = tree,
				Root = rt,
				Background = ((Component)rt).GetComponent<Image>(),
				Accent = a