Decompiled source of LateGamePerformance v1.5.0

LateGamePerformance.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.FalseSon;
using EntityStates.ScavBackpack;
using HarmonyLib;
using LateGamePerformance.Patches;
using LateGamePerformance.Ui;
using Microsoft.CodeAnalysis;
using Rewired;
using RoR2;
using RoR2.Navigation;
using RoR2.Skills;
using RoR2.UI;
using RoR2.UI.SkinControllers;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LateGamePerformance
{
	internal sealed class DpsHud : MonoBehaviour
	{
		private sealed class RowView
		{
			internal RectTransform root;

			internal Image bar;

			internal HGTextMeshProUGUI name;

			internal HGTextMeshProUGUI damage;

			internal HGTextMeshProUGUI share;

			internal HGTextMeshProUGUI dps;

			internal HGTextMeshProUGUI now;
		}

		private const float Width = 470f;

		private const float Pad = 14f;

		private const float TitleHeight = 30f;

		private const float ColumnHeight = 20f;

		private const float RowHeight = 30f;

		private const float FooterHeight = 22f;

		private const float NameWidth = 150f;

		private const float DamageWidth = 78f;

		private const float ShareWidth = 56f;

		private const float DpsWidth = 66f;

		private const float NowWidth = 72f;

		private static readonly Color[] Ranks = (Color[])(object)new Color[3]
		{
			new Color(1f, 0.82f, 0.36f, 1f),
			new Color(0.8f, 0.84f, 0.9f, 1f),
			new Color(0.79f, 0.55f, 0.36f, 1f)
		};

		private Canvas canvas;

		private RectTransform panel;

		private RectTransform rowRoot;

		private HGTextMeshProUGUI clock;

		private HGTextMeshProUGUI footer;

		private readonly List<RowView> views = new List<RowView>();

		private bool hidden;

		internal static DpsHud Instance { get; private set; }

		internal static void Install(GameObject host)
		{
			Instance = host.AddComponent<DpsHud>();
		}

		private void Update()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (DpsMeterPatch.Active && DpsMeterPatch.ToggleKey != null)
			{
				KeyboardShortcut value = DpsMeterPatch.ToggleKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					hidden = !hidden;
				}
			}
			if (!DpsMeterPatch.Active || hidden || !DpsMeterPatch.ShowDuringRun.Value || !Object.op_Implicit((Object)(object)Run.instance) || !Object.op_Implicit((Object)(object)Stage.instance) || ModMenu.IsOpen)
			{
				UiFactory.SetVisible(canvas, visible: false);
				return;
			}
			GameSkin.Refresh();
			if (GameSkin.Ready)
			{
				if ((Object)(object)canvas == (Object)null)
				{
					Build();
				}
				UiFactory.SetVisible(canvas, visible: true);
				Refresh();
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)canvas != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)canvas).gameObject);
			}
		}

		private void Build()
		{
			//IL_0054: 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_0078: 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_00a2: 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_01b2: Expected O, but got Unknown
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			canvas = UiFactory.CreateCanvas("LGP_DamageMeter", 100, interactive: false);
			panel = UiFactory.Panel(((Component)canvas).transform, "Panel");
			float value = DpsMeterPatch.PanelX.Value;
			float num = 1f - DpsMeterPatch.PanelY.Value;
			panel.anchorMin = new Vector2(value, num);
			panel.anchorMax = new Vector2(value, num);
			panel.pivot = new Vector2(value, num);
			panel.anchoredPosition = Vector2.zero;
			panel.sizeDelta = new Vector2(470f, 200f);
			UiFactory.Row(((TMP_Text)UiFactory.Label((Transform)(object)panel, "Title", "DAMAGE THIS STAGE", GameSkin.TextKind.Header, 22f, (TextAlignmentOptions)513)).rectTransform, 14f, 442f, 14f, 30f);
			clock = UiFactory.Label((Transform)(object)panel, "Clock", "0:00", GameSkin.TextKind.Header, 22f, (TextAlignmentOptions)516);
			UiFactory.Row(((TMP_Text)clock).rectTransform, 14f, 442f, 14f, 30f);
			float num2 = 44f;
			Column("Player", (TextAlignmentOptions)513, 0, num2);
			Column("Damage", (TextAlignmentOptions)516, 1, num2);
			Column("Share", (TextAlignmentOptions)516, 2, num2);
			Column("DPS", (TextAlignmentOptions)516, 3, num2);
			Column("Now 6s", (TextAlignmentOptions)516, 4, num2);
			GameObject val = new GameObject("Rows", new Type[1] { typeof(RectTransform) });
			rowRoot = val.GetComponent<RectTransform>();
			((Transform)rowRoot).SetParent((Transform)(object)panel, false);
			UiFactory.Row(rowRoot, 0f, 470f, num2 + 20f, 0f);
			footer = UiFactory.Label((Transform)(object)panel, "Footer", string.Empty, GameSkin.TextKind.Body, 15f, (TextAlignmentOptions)513);
			((Graphic)footer).color = GameSkin.QuietColor;
		}

		private void Column(string text, TextAlignmentOptions alignment, int index, float top)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			HGTextMeshProUGUI obj = UiFactory.Label((Transform)(object)panel, "Column" + text, text, GameSkin.TextKind.Body, 16f, alignment);
			((Graphic)obj).color = GameSkin.QuietColor;
			UiFactory.Row(((TMP_Text)obj).rectTransform, 14f + OffsetOf(index), WidthOf(index), top, 20f);
		}

		private static float WidthOf(int index)
		{
			return index switch
			{
				0 => 150f, 
				1 => 78f, 
				2 => 56f, 
				3 => 66f, 
				_ => 72f, 
			};
		}

		private static float OffsetOf(int index)
		{
			float num = 0f;
			for (int i = 0; i < index; i++)
			{
				num += WidthOf(i);
			}
			return num;
		}

		private RowView CreateRow(int index)
		{
			//IL_0024: 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)
			RectTransform component = new GameObject("Row" + index, new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)rowRoot, false);
			UiFactory.Row(component, 0f, 470f, (float)index * 30f, 30f);
			RowView obj = new RowView
			{
				root = component,
				bar = UiFactory.Fill((Transform)(object)component, "Bar", new Color(1f, 1f, 1f, 0.16f))
			};
			UiFactory.Row(((Graphic)obj.bar).rectTransform, 7f, 456f, 2f, 26f);
			obj.name = Cell(component, "Name", 0, (TextAlignmentOptions)513, 20f, GameSkin.TextKind.Body);
			obj.damage = Cell(component, "Damage", 1, (TextAlignmentOptions)516, 20f, GameSkin.TextKind.Header);
			obj.share = Cell(component, "Share", 2, (TextAlignmentOptions)516, 19f, GameSkin.TextKind.Body);
			obj.dps = Cell(component, "Dps", 3, (TextAlignmentOptions)516, 19f, GameSkin.TextKind.Body);
			obj.now = Cell(component, "Now", 4, (TextAlignmentOptions)516, 20f, GameSkin.TextKind.Header);
			return obj;
		}

		private static HGTextMeshProUGUI Cell(RectTransform parent, string name, int index, TextAlignmentOptions alignment, float size, GameSkin.TextKind kind)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			HGTextMeshProUGUI obj = UiFactory.Label((Transform)(object)parent, name, string.Empty, kind, size, alignment);
			UiFactory.Row(((TMP_Text)obj).rectTransform, 14f + OffsetOf(index), WidthOf(index), 0f, 30f);
			return obj;
		}

		private void Refresh()
		{
			//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_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: 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_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			List<DpsMeterPatch.Row> list = DpsMeterPatch.Snapshot();
			while (views.Count < list.Count)
			{
				views.Add(CreateRow(views.Count));
			}
			for (int i = list.Count; i < views.Count; i++)
			{
				((Component)views[i].root).gameObject.SetActive(false);
			}
			float stageSeconds = DpsMeterPatch.StageSeconds;
			double num = 0.0;
			for (int j = 0; j < list.Count; j++)
			{
				num += list[j].total;
			}
			double num2 = ((list.Count > 0) ? list[0].total : 0.0);
			for (int k = 0; k < list.Count; k++)
			{
				DpsMeterPatch.Row row = list[k];
				RowView rowView = views[k];
				((Component)rowView.root).gameObject.SetActive(true);
				Color val = ((k < Ranks.Length && row.total > 0.0) ? Ranks[k] : GameSkin.BodyColor);
				((Graphic)rowView.name).color = val;
				((TMP_Text)rowView.name).text = row.name;
				((TMP_Text)rowView.damage).text = Short(row.total);
				((TMP_Text)rowView.share).text = ((num > 0.0) ? (((float)(row.total / num) * 100f).ToString("0", CultureInfo.InvariantCulture) + "%") : "-");
				((TMP_Text)rowView.dps).text = Short((stageSeconds > 0.5f) ? (row.total / (double)stageSeconds) : 0.0);
				((TMP_Text)rowView.now).text = Short(row.Recent);
				float num3 = ((num2 > 0.0) ? Mathf.Clamp01((float)(row.total / num2)) : 0f);
				((Graphic)rowView.bar).color = new Color(val.r, val.g, val.b, 0.2f);
				((Graphic)rowView.bar).rectTransform.sizeDelta = new Vector2(456f * num3, 26f);
			}
			((TMP_Text)clock).text = Clock(stageSeconds);
			HGTextMeshProUGUI obj = footer;
			string arg = Short(num);
			KeyboardShortcut value = DpsMeterPatch.ToggleKey.Value;
			((TMP_Text)obj).text = $"Total {arg}   -   {((KeyboardShortcut)(ref value)).MainKey} hides this";
			float num4 = 64f;
			float num5 = num4 + (float)list.Count * 30f + 22f + 14f;
			panel.sizeDelta = new Vector2(470f, num5);
			UiFactory.Row(((TMP_Text)footer).rectTransform, 14f, 442f, num4 + (float)list.Count * 30f + 2f, 22f);
		}

		private static string Clock(float seconds)
		{
			int num = Mathf.Max(0, Mathf.FloorToInt(seconds));
			return (num / 60).ToString(CultureInfo.InvariantCulture) + ":" + (num % 60).ToString("00", CultureInfo.InvariantCulture);
		}

		private static string Short(double value)
		{
			if (value >= 1000000.0)
			{
				return (value / 1000000.0).ToString("0.0", CultureInfo.InvariantCulture) + "M";
			}
			if (value >= 1000.0)
			{
				return (value / 1000.0).ToString("0.0", CultureInfo.InvariantCulture) + "k";
			}
			return value.ToString("0", CultureInfo.InvariantCulture);
		}
	}
	internal static class MenuCatalog
	{
		private sealed class Entry
		{
			internal string Category;

			internal string Title;

			internal string Blurb;
		}

		internal const string Gameplay = "Gameplay";

		internal const string Maintenance = "Fixes and performance";

		private static readonly Dictionary<string, Entry> features = new Dictionary<string, Entry>
		{
			["SkipIntro"] = new Entry
			{
				Category = "Gameplay",
				Title = "Skip the intro video",
				Blurb = "Cuts the engine logo and the ship cutscene, so the game goes almost straight to the title screen."
			},
			["CritOverstack"] = new Entry
			{
				Category = "Gameplay",
				Title = "Crit overstacking",
				Blurb = "Crit chance above 100 percent turns into extra crit damage instead of counting for nothing."
			},
			["AutoSprint"] = new Entry
			{
				Category = "Gameplay",
				Title = "Automatic sprint",
				Blurb = "Your character sprints while it moves. Hold the sprint key to walk instead."
			},
			["EmptyChests"] = new Entry
			{
				Category = "Gameplay",
				Title = "Clear empty chests",
				Blurb = "Opened chests, used barrels, and spent shops disappear."
			},
			["Sharing"] = new Entry
			{
				Category = "Gameplay",
				Title = "Share items and money",
				Blurb = "An item one player picks up goes to everybody, and every player gets the full gold. Only the host needs this mod. Off by default, because it makes a group much stronger than the base game intends."
			},
			["DpsMeter"] = new Entry
			{
				Category = "Gameplay",
				Title = "Damage meter",
				Blurb = "A table on screen shows the damage each player did on the stage you are on. It also gives the share of the total and damage per second."
			},
			["StatPoints"] = new Entry
			{
				Category = "Gameplay",
				Title = "Character stat points",
				Blurb = "Earn a point every few character levels and spend it on health, damage, attack speed, crit, armor, regeneration, or speed. Press F3 during a run, or click the badge, to open the point window. Only the host can spend. A player who joins sees the window, but the buttons stay off there. The stats would never reach the machine that runs the game."
			},
			["BugFixes"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Fix game bugs",
				Blurb = "Stops errors that the base game throws during play."
			},
			["BuffStatsFilter"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Faster damage-over-time ticks",
				Blurb = "Bleed and poison stacks no longer recalculate every stat on every tick."
			},
			["NavPathBudget"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Spread out enemy pathfinding",
				Blurb = "Spreads the path work of an enemy wave over several frames."
			},
			["TargetSearchGc"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Cheaper target search",
				Blurb = "Missiles, drones, and turrets no longer create garbage when they look for a target."
			},
			["DamageNumberBatch"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Faster damage numbers",
				Blurb = "Big hits no longer slow the game down with damage numbers."
			},
			["RaycastThrottle"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Cheaper enemy steering",
				Blurb = "Enemies check for obstacles less often."
			},
			["HealthBarThrottle"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Cheaper health bars",
				Blurb = "Health bars refresh on a timer instead of every frame."
			},
			["TeamItemCountCache"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Faster teleporter events",
				Blurb = "Stops repeated scans of every character during a teleporter fight."
			},
			["ModelCameraPass"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Cheaper character drawing",
				Blurb = "The camera examines every character once instead of twice, and skips the work for characters that draw nothing."
			},
			["PerfReadout"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Performance readout",
				Blurb = "Frame times and entity counts in the log. The panel starts closed. Press F6 to show it or hide it."
			},
			["FixedTimeCatchup"] = new Entry
			{
				Category = "Fixes and performance",
				Title = "Stop freeze spirals",
				Blurb = "Under heavy load the game slows down for a moment instead of freezing."
			}
		};

		private static readonly HashSet<string> playerFacing = new HashSet<string>
		{
			"Menu/ToggleKey", "SkipIntro/AlsoSkipLogoScreen", "Sharing/ShareItems", "Sharing/ShareMoney", "Sharing/ShareWhiteItems", "Sharing/ShareGreenItems", "Sharing/ShareRedItems", "Sharing/ShareBossItems", "Sharing/ShareLunarItems", "Sharing/ShareVoidItems",
			"Sharing/ShareToDeadPlayers", "Sharing/ShareEquipment", "Sharing/DropReplacedEquipment", "Sharing/SharePrinterOutput", "Sharing/ScaleSharedLoot", "Sharing/MoneyShareScalar", "EmptyChests/Chests", "EmptyChests/Barrels", "EmptyChests/Multishops", "EmptyChests/ScavengerBags",
			"EmptyChests/DelaySeconds", "AutoSprint/HoldSprintKeyToWalk", "AutoSprint/HoldOffSeconds", "DpsMeter/ShowDuringRun", "DpsMeter/ToggleKey", "DpsMeter/IncludeMinions", "DpsMeter/CountAllDamage", "DpsMeter/PanelX", "DpsMeter/PanelY", "StatPoints/ShowBadge",
			"StatPoints/OpenKey", "StatPoints/BadgeX", "StatPoints/BadgeY", "StatPoints/CharacterLevelsPerPoint", "StatPoints/MaxPointsPerStat", "StatPoints/HealthPerPoint", "StatPoints/RegenerationPerPoint", "StatPoints/DamagePerPoint", "StatPoints/AttackSpeedPerPoint", "StatPoints/CritChancePerPoint",
			"StatPoints/ArmorPerPoint", "StatPoints/MoveSpeedPerPoint", "FixedTimeCatchup/MaxCatchUpTicks", "ModelCameraPass/OverlayFrameStride", "PerfReadout/ShowPanel", "PerfReadout/ToggleKey", "PerfReadout/LogSeconds"
		};

		internal static bool IsPlayerFacing(string section, string key)
		{
			return playerFacing.Contains(section + "/" + key);
		}

		internal static string CategoryOf(string featureKey)
		{
			if (!features.TryGetValue(featureKey, out var value))
			{
				return "Gameplay";
			}
			return value.Category;
		}

		internal static string TitleOf(string featureKey)
		{
			if (!features.TryGetValue(featureKey, out var value))
			{
				return featureKey;
			}
			return value.Title;
		}

		internal static string BlurbOf(string featureKey, string fallback)
		{
			if (!features.TryGetValue(featureKey, out var value))
			{
				return fallback;
			}
			return value.Blurb;
		}
	}
	internal sealed class ModMenu : MonoBehaviour
	{
		private const float WindowWidth = 1000f;

		private const float WindowHeight = 620f;

		private const float ListWidth = 340f;

		private static ConfigEntry<bool> showEverySetting;

		private Canvas canvas;

		private RectTransform listContent;

		private RectTransform detailContent;

		private HGTextMeshProUGUI detailTitle;

		private HGTextMeshProUGUI detailBlurb;

		private HGTextMeshProUGUI detailState;

		private Button showEveryButton;

		private readonly List<SettingRow> rows = new List<SettingRow>();

		private readonly List<HGTextMeshProUGUI> listLabels = new List<HGTextMeshProUGUI>();

		private readonly List<HGTextMeshProUGUI> listPicks = new List<HGTextMeshProUGUI>();

		private readonly List<PatchRegistry.Group> listGroups = new List<PatchRegistry.Group>();

		private string selectedKey;

		private bool listDirty = true;

		private bool detailDirty = true;

		private readonly CursorHold cursor = new CursorHold();

		private ConfigEntryBase awaitingBind;

		private SettingRow awaitingRow;

		internal static ModMenu Instance { get; private set; }

		internal static bool IsOpen { get; private set; }

		internal static ConfigEntry<KeyboardShortcut> Hotkey { get; private set; }

		internal static void Install(Harmony harmony, GameObject host)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			Hotkey = Plugin.Cfg.Bind<KeyboardShortcut>("Menu", "ToggleKey", new KeyboardShortcut((KeyCode)285, Array.Empty<KeyCode>()), "Key that opens and closes the settings page.");
			showEverySetting = Plugin.Cfg.Bind<bool>("Menu", "ShowEverySetting", false, "Also show the fine-tuning values that most players never need.");
			harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerCharacterMasterController), "CanSendBodyInput", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ModMenu), "BlockInputPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Instance = host.AddComponent<ModMenu>();
		}

		private static void BlockInputPostfix(ref bool __result, ref bool onlyAllowMovement)
		{
			if (IsOpen || StatPointsWindow.IsOpen)
			{
				__result = false;
				onlyAllowMovement = false;
			}
		}

		internal static void Close()
		{
			Instance?.SetOpen(open: false);
		}

		internal static void OpenAt(string featureKey)
		{
			if (!((Object)(object)Instance == (Object)null))
			{
				Instance.selectedKey = featureKey;
				Instance.detailDirty = true;
				Instance.SetOpen(open: true);
			}
		}

		private void Update()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (awaitingBind != null)
			{
				CaptureKey();
			}
			else if (Hotkey != null)
			{
				KeyboardShortcut value = Hotkey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					SetOpen(!IsOpen);
				}
			}
			if (!IsOpen)
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				SetOpen(open: false);
				return;
			}
			cursor.Set(wanted: true);
			GameSkin.Refresh();
			if (GameSkin.Ready)
			{
				if ((Object)(object)canvas == (Object)null)
				{
					Build();
				}
				if (listDirty)
				{
					BuildList();
				}
				if (detailDirty)
				{
					BuildDetail();
				}
				RefreshListState();
			}
		}

		private void OnDisable()
		{
			SetOpen(open: false);
		}

		private void OnDestroy()
		{
			if ((Object)(object)canvas != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)canvas).gameObject);
			}
		}

		private void SetOpen(bool open)
		{
			if (open != IsOpen)
			{
				IsOpen = open;
				awaitingBind = null;
				awaitingRow = null;
				UiFactory.SetVisible(canvas, open);
				if (open)
				{
					detailDirty = true;
				}
				else
				{
					cursor.Release();
				}
			}
		}

		private void CaptureKey()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0036: Invalid comparison between Unknown and I4
			//IL_003e: 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)
			if (!Input.anyKeyDown)
			{
				return;
			}
			foreach (KeyCode value in Enum.GetValues(typeof(KeyCode)))
			{
				if (Input.GetKeyDown(value))
				{
					if ((int)value != 27)
					{
						awaitingBind.BoxedValue = (object)new KeyboardShortcut(value, Array.Empty<KeyCode>());
					}
					awaitingRow?.Refresh();
					awaitingRow?.SetBindPrompt(waiting: false);
					awaitingBind = null;
					awaitingRow = null;
					break;
				}
			}
		}

		private void Build()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			canvas = UiFactory.CreateCanvas("LGP_Settings", 200, interactive: true);
			Image obj = UiFactory.Fill(((Component)canvas).transform, "Dim", new Color(0f, 0f, 0f, 0.66f));
			UiFactory.Stretch(((Graphic)obj).rectTransform);
			((Graphic)obj).raycastTarget = true;
			RectTransform obj2 = UiFactory.Panel(((Component)canvas).transform, "Window", GameSkin.PanelKind.Main, opaque: true);
			obj2.anchorMin = new Vector2(0.5f, 0.5f);
			obj2.anchorMax = new Vector2(0.5f, 0.5f);
			obj2.pivot = new Vector2(0.5f, 0.5f);
			obj2.anchoredPosition = Vector2.zero;
			obj2.sizeDelta = new Vector2(1000f, 620f);
			RectTransform obj3 = UiFactory.Vertical((Transform)(object)obj2, "Body", 10f, 18);
			UiFactory.Stretch(obj3);
			RectTransform parent = UiFactory.Horizontal((Transform)(object)obj3, "TitleBar", 10f, 34f);
			UiFactory.Size((Component)(object)UiFactory.Label((Transform)(object)parent, "Title", "LateGamePerformance  1.5.0", GameSkin.TextKind.Header, 26f, (TextAlignmentOptions)513), 800f, 32f);
			UiFactory.Size((Component)(object)UiFactory.Button((Transform)(object)parent, "Close", "Close", delegate
			{
				SetOpen(open: false);
			}), 120f, 32f);
			RectTransform obj4 = UiFactory.Horizontal((Transform)(object)obj3, "Columns", 16f, 0f);
			UiFactory.Size((Component)(object)obj4, 0f, 530f);
			RectTransform val = UiFactory.Vertical((Transform)(object)obj4, "Left", 8f);
			UiFactory.Size((Component)(object)val, 340f, 530f);
			listContent = UiFactory.Scroll((Transform)(object)val, "FeatureList", out var scroll);
			UiFactory.Size((Component)(object)scroll, 340f, 480f);
			showEveryButton = UiFactory.Button((Transform)(object)val, "ShowEvery", string.Empty, delegate
			{
				showEverySetting.Value = !showEverySetting.Value;
				listDirty = true;
				detailDirty = true;
			});
			UiFactory.Size((Component)(object)showEveryButton, 340f, 34f);
			RectTransform val2 = UiFactory.Vertical((Transform)(object)obj4, "Right", 6f);
			UiFactory.Size((Component)(object)val2, 608f, 530f);
			detailTitle = UiFactory.Label((Transform)(object)val2, "DetailTitle", string.Empty, GameSkin.TextKind.Header, 24f, (TextAlignmentOptions)513);
			UiFactory.Size((Component)(object)detailTitle, 0f, 30f);
			detailBlurb = UiFactory.Label((Transform)(object)val2, "DetailBlurb", string.Empty, GameSkin.TextKind.Body, 17f, (TextAlignmentOptions)257);
			((TMP_Text)detailBlurb).enableWordWrapping = true;
			UiFactory.Size((Component)(object)detailBlurb, 0f, 64f);
			detailState = UiFactory.Label((Transform)(object)val2, "DetailState", string.Empty, GameSkin.TextKind.Body, 16f, (TextAlignmentOptions)513);
			((Graphic)detailState).color = GameSkin.QuietColor;
			UiFactory.Size((Component)(object)detailState, 0f, 22f);
			detailContent = UiFactory.Scroll((Transform)(object)val2, "Detail", out var scroll2);
			UiFactory.Size((Component)(object)scroll2, 608f, 400f);
			listDirty = true;
			detailDirty = true;
		}

		private void BuildList()
		{
			listDirty = false;
			Clear(listContent);
			listLabels.Clear();
			listPicks.Clear();
			listGroups.Clear();
			AddCategory("Gameplay");
			if (showEverySetting.Value)
			{
				AddCategory("Fixes and performance");
			}
			HGTextMeshProUGUI componentInChildren = ((Component)showEveryButton).GetComponentInChildren<HGTextMeshProUGUI>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((TMP_Text)componentInChildren).text = (showEverySetting.Value ? "Hide fixes and tuning" : "Show fixes and tuning");
			}
		}

		private void AddCategory(string category)
		{
			UiFactory.Size((Component)(object)UiFactory.Label((Transform)(object)listContent, "Header" + category, category.ToUpperInvariant(), GameSkin.TextKind.Header, 17f, (TextAlignmentOptions)513), 0f, 26f);
			IReadOnlyList<PatchRegistry.Group> groups = PatchRegistry.Groups;
			for (int i = 0; i < groups.Count; i++)
			{
				PatchRegistry.Group obj = groups[i];
				if (!(MenuCatalog.CategoryOf(obj.Key) != category))
				{
					if (string.IsNullOrEmpty(selectedKey))
					{
						selectedKey = obj.Key;
					}
					RectTransform parent = UiFactory.Horizontal((Transform)(object)listContent, "Row" + obj.Key, 8f, 34f);
					PatchRegistry.Group captured = obj;
					Button val = UiFactory.Button((Transform)(object)parent, "Toggle", string.Empty, delegate
					{
						PatchRegistry.SetEnabled(captured, !captured.Active);
					});
					UiFactory.Size((Component)(object)val, 62f, 30f);
					Button obj2 = UiFactory.Button((Transform)(object)parent, "Pick", MenuCatalog.TitleOf(obj.Key), delegate
					{
						selectedKey = captured.Key;
						detailDirty = true;
					});
					UiFactory.Size((Component)(object)obj2, 254f, 30f);
					HGTextMeshProUGUI componentInChildren = ((Component)obj2).GetComponentInChildren<HGTextMeshProUGUI>();
					if ((Object)(object)componentInChildren != (Object)null)
					{
						((TMP_Text)componentInChildren).alignment = (TextAlignmentOptions)513;
						((TMP_Text)componentInChildren).fontSize = 17f;
					}
					listLabels.Add(((Component)val).GetComponentInChildren<HGTextMeshProUGUI>());
					listPicks.Add(componentInChildren);
					listGroups.Add(obj);
				}
			}
		}

		private void RefreshListState()
		{
			//IL_00ac: 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_004f: 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)
			for (int i = 0; i < listGroups.Count && i < listLabels.Count; i++)
			{
				HGTextMeshProUGUI val = listLabels[i];
				if ((Object)(object)val != (Object)null)
				{
					bool active = listGroups[i].Active;
					((TMP_Text)val).text = (active ? "ON" : "OFF");
					((Graphic)val).color = (active ? GameSkin.HeaderColor : GameSkin.QuietColor);
				}
				if (i < listPicks.Count && (Object)(object)listPicks[i] != (Object)null)
				{
					((Graphic)listPicks[i]).color = ((listGroups[i].Key == selectedKey) ? GameSkin.HeaderColor : GameSkin.BodyColor);
				}
			}
		}

		private void BuildDetail()
		{
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			detailDirty = false;
			Clear(detailContent);
			rows.Clear();
			PatchRegistry.Group obj = FindSelected();
			if (obj == null)
			{
				return;
			}
			((TMP_Text)detailTitle).text = MenuCatalog.TitleOf(obj.Key);
			((TMP_Text)detailBlurb).text = MenuCatalog.BlurbOf(obj.Key, obj.Description);
			((TMP_Text)detailState).text = (obj.Active ? "Turned on" : "Turned off");
			if (!string.IsNullOrEmpty(obj.Error))
			{
				HGTextMeshProUGUI obj2 = detailState;
				((TMP_Text)obj2).text = ((TMP_Text)obj2).text + "   -   last error: " + obj.Error;
			}
			int num = 0;
			ConfigEntryBase[] configEntries = Plugin.Cfg.GetConfigEntries();
			foreach (ConfigEntryBase val in configEntries)
			{
				if (!(val.Definition.Section != obj.Key) && (showEverySetting.Value || MenuCatalog.IsPlayerFacing(obj.Key, val.Definition.Key)))
				{
					rows.Add(SettingRow.Create((Transform)(object)detailContent, val, RequestBind));
					num++;
				}
			}
			if (num == 0)
			{
				HGTextMeshProUGUI obj3 = UiFactory.Label((Transform)(object)detailContent, "None", "Nothing to set for this one.", GameSkin.TextKind.Body, 17f, (TextAlignmentOptions)513);
				((Graphic)obj3).color = GameSkin.QuietColor;
				UiFactory.Size((Component)(object)obj3, 0f, 26f);
			}
			HGTextMeshProUGUI obj4 = UiFactory.Label((Transform)(object)detailContent, "Note", "Changes save by themselves.", GameSkin.TextKind.Body, 15f, (TextAlignmentOptions)513);
			((Graphic)obj4).color = GameSkin.QuietColor;
			UiFactory.Size((Component)(object)obj4, 0f, 24f);
		}

		private void RequestBind(ConfigEntryBase entry)
		{
			awaitingBind = entry;
			awaitingRow = null;
			for (int i = 0; i < rows.Count; i++)
			{
				bool flag = rows[i].Entry == entry;
				rows[i].SetBindPrompt(flag);
				if (flag)
				{
					awaitingRow = rows[i];
				}
			}
		}

		private PatchRegistry.Group FindSelected()
		{
			IReadOnlyList<PatchRegistry.Group> groups = PatchRegistry.Groups;
			for (int i = 0; i < groups.Count; i++)
			{
				if (groups[i].Key == selectedKey)
				{
					return groups[i];
				}
			}
			if (groups.Count <= 0)
			{
				return null;
			}
			return groups[0];
		}

		private static void Clear(RectTransform parent)
		{
			if (!((Object)(object)parent == (Object)null))
			{
				for (int num = ((Transform)parent).childCount - 1; num >= 0; num--)
				{
					Object.Destroy((Object)(object)((Component)((Transform)parent).GetChild(num)).gameObject);
				}
			}
		}
	}
	internal static class PatchGroups
	{
		internal static void RegisterAll()
		{
			PatchRegistry.Register("BuffStatsFilter", "Skip full stat recalculation when a pure damage-over-time buff changes count. Bleed and poison stacks no longer force a stat pass per tick.", defaultOn: true, BuffStatsFilterPatch.Apply);
			PatchRegistry.Register("NavPathBudget", "Limit synchronous AI path computations per physics tick and stagger repath timers. The game ships this throttle in a broken state.", defaultOn: true, NavPathBudgetPatch.Apply);
			PatchRegistry.Register("TargetSearchGc", "Remove per-call allocations from target searches used by missiles, drones, turrets, and AI.", defaultOn: true, TargetSearchGcPatch.Apply);
			PatchRegistry.Register("DamageNumberBatch", "Batch damage-number particle writes to one copy per frame instead of one per number.", defaultOn: true, DamageNumberBatchPatch.Apply, DamageNumberBatchPatch.Unapply);
			PatchRegistry.Register("RaycastThrottle", "Throttle AI obstruction raycasts to the interval the game defines but never uses.", defaultOn: true, RaycastThrottlePatch.Apply);
			PatchRegistry.Register("HealthBarThrottle", "Restore the health-bar update throttle that the game defeats on load.", defaultOn: true, HealthBarThrottlePatch.Apply);
			PatchRegistry.Register("TeamItemCountCache", "Cache team item counts briefly. Removes repeated full scans of all characters during teleporter events.", defaultOn: true, TeamItemCountCachePatch.Apply, TeamItemCountCachePatch.Unapply);
			PatchRegistry.Register("ModelCameraPass", "One camera pass over character models instead of two, and a frame stride on the overlay scan. The base game measures hurtbox distances for models that draw nothing.", defaultOn: true, ModelCameraPassPatch.Apply);
			PatchRegistry.Register("PerfReadout", "Frame times and entity counts on screen and in the log.", defaultOn: true, PerfReadoutPatch.Apply, PerfReadoutPatch.Unapply);
			PatchRegistry.Register("FixedTimeCatchup", "Clamp physics catch-up so a slow frame cannot snowball into a freeze. The game slows down under extreme load instead.", defaultOn: true, FixedTimeCatchupPatch.Apply, FixedTimeCatchupPatch.Unapply);
			PatchRegistry.Register("SkipIntro", "Boot straight to the title screen without the startup video.", defaultOn: true, SkipIntroPatch.Apply, SkipIntroPatch.Unapply);
			PatchRegistry.Register("CritOverstack", "Crit chance above 100 percent converts into extra crit damage.", defaultOn: true, CritOverstackPatch.Apply);
			PatchRegistry.Register("BugFixes", "Guards for vanilla code that throws exceptions during normal play.", defaultOn: true, BugFixesPatch.Apply);
			PatchRegistry.Register("Sharing", "Item and money sharing between players. Off by default, because it changes the balance of the run for every player. Host-side, clients need no mod.", defaultOn: false, SharingPatch.Apply);
			PatchRegistry.Register("EmptyChests", "Remove opened chests, used barrels, and spent multishops after a delay.", defaultOn: true, EmptyChestsPatch.Apply, EmptyChestsPatch.Unapply);
			PatchRegistry.Register("AutoSprint", "Sprint turns on by itself while moving.", defaultOn: true, AutoSprintPatch.Apply, AutoSprintPatch.Unapply);
			PatchRegistry.Register("DpsMeter", "Damage per player for the stage you are on. Shows every connected player.", defaultOn: true, DpsMeterPatch.Apply, DpsMeterPatch.Unapply);
			PatchRegistry.Register("StatPoints", "Earn points as your character levels and spend them on stats. Works with every survivor.", defaultOn: true, StatPointsPatch.Apply, StatPointsPatch.Unapply);
		}
	}
	internal static class PatchRegistry
	{
		internal delegate void GroupApplier(Harmony harmony);

		internal delegate void GroupReverter();

		internal sealed class Group
		{
			internal string Key;

			internal string Description;

			internal bool DefaultOn;

			internal GroupApplier Apply;

			internal GroupReverter Revert;

			internal ConfigEntry<bool> Toggle;

			internal Harmony Harmony;

			internal bool Active;

			internal string Error;
		}

		private static readonly List<Group> groups = new List<Group>();

		internal static IReadOnlyList<Group> Groups => groups;

		internal static void Register(string key, string description, bool defaultOn, GroupApplier apply, GroupReverter revert = null)
		{
			groups.Add(new Group
			{
				Key = key,
				Description = description,
				DefaultOn = defaultOn,
				Apply = apply,
				Revert = revert
			});
		}

		internal static int ApplyAll()
		{
			PatchGroups.RegisterAll();
			int num = 0;
			foreach (Group group in groups)
			{
				group.Toggle = Plugin.Cfg.Bind<bool>("Features", group.Key, group.DefaultOn, group.Description);
				Group captured = group;
				captured.Toggle.SettingChanged += delegate
				{
					if (captured.Toggle.Value)
					{
						Enable(captured);
					}
					else
					{
						Disable(captured);
					}
				};
				if (group.Toggle.Value && Enable(group))
				{
					num++;
				}
			}
			return num;
		}

		internal static bool Enable(Group group)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			if (group.Active)
			{
				return true;
			}
			group.Harmony = new Harmony("com.tim.LateGamePerformance." + group.Key);
			try
			{
				group.Apply(group.Harmony);
				group.Active = true;
				group.Error = null;
				return true;
			}
			catch (Exception ex)
			{
				group.Error = ex.Message;
				Plugin.Log.LogError((object)$"Feature '{group.Key}' failed and is off: {ex}");
				try
				{
					group.Harmony.UnpatchSelf();
				}
				catch (Exception)
				{
				}
				group.Harmony = null;
				return false;
			}
		}

		internal static void Disable(Group group)
		{
			if (group.Active)
			{
				try
				{
					group.Revert?.Invoke();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Feature '" + group.Key + "' did not clean up: " + ex.Message));
				}
				Harmony harmony = group.Harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
				group.Harmony = null;
				group.Active = false;
			}
		}

		internal static void SetEnabled(Group group, bool enabled)
		{
			if (group.Toggle != null)
			{
				group.Toggle.Value = enabled;
			}
			if (enabled)
			{
				Enable(group);
			}
			else
			{
				Disable(group);
			}
		}

		internal static void DisableAll()
		{
			foreach (Group group in groups)
			{
				Disable(group);
			}
		}
	}
	internal sealed class PerfHud : MonoBehaviour
	{
		private const int SampleCount = 512;

		private const float PeakWindowSeconds = 10f;

		private const float Width = 290f;

		private const float Pad = 14f;

		private const float TitleHeight = 28f;

		private const float LineHeight = 22f;

		private static readonly string[] Titles = new string[8] { "Frame", "FPS", "Peak 10s", "Peak run", "Monsters", "Hurtboxes", "GC0 / s", "Heap" };

		private readonly float[] samples = new float[512];

		private int sampleIndex;

		private int sampleFill;

		private readonly float[] secondPeaks = new float[10];

		private int lastSecond = -1;

		private float runPeakFrame;

		private int lastGcCount;

		private float gcStamp;

		private float gcPerSecond;

		private float nextLog;

		private bool wasRunning;

		private Canvas canvas;

		private HGTextMeshProUGUI[] values;

		internal static PerfHud Instance { get; private set; }

		internal static void Install(GameObject host)
		{
			Instance = host.AddComponent<PerfHud>();
		}

		private void Update()
		{
			//IL_001b: 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)
			if (!PerfReadoutPatch.Active)
			{
				Show(visible: false);
				return;
			}
			if (PerfReadoutPatch.ToggleKey != null)
			{
				KeyboardShortcut value = PerfReadoutPatch.ToggleKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					PerfReadoutPatch.ShowPanel.Value = !PerfReadoutPatch.ShowPanel.Value;
				}
			}
			Sample();
			if (!PerfReadoutPatch.ShowPanel.Value || !Object.op_Implicit((Object)(object)Run.instance) || ModMenu.IsOpen || StatPointsWindow.IsOpen)
			{
				Show(visible: false);
				return;
			}
			GameSkin.Refresh();
			if (GameSkin.Ready)
			{
				if ((Object)(object)canvas == (Object)null)
				{
					Build();
				}
				Show(visible: true);
				WriteValues();
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)canvas != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)canvas).gameObject);
			}
		}

		private void Show(bool visible)
		{
			UiFactory.SetVisible(canvas, visible);
		}

		private void Sample()
		{
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			samples[sampleIndex] = unscaledDeltaTime;
			sampleIndex = (sampleIndex + 1) % 512;
			if (sampleFill < 512)
			{
				sampleFill++;
			}
			float unscaledTime = Time.unscaledTime;
			RollPeaks(Mathf.FloorToInt(unscaledTime), unscaledDeltaTime);
			if (!Object.op_Implicit((Object)(object)Run.instance))
			{
				runPeakFrame = 0f;
			}
			else if (unscaledDeltaTime > runPeakFrame)
			{
				runPeakFrame = unscaledDeltaTime;
			}
			if (unscaledTime - gcStamp >= 1f)
			{
				int num = GC.CollectionCount(0);
				gcPerSecond = (float)(num - lastGcCount) / (unscaledTime - gcStamp);
				lastGcCount = num;
				gcStamp = unscaledTime;
			}
			float value = PerfReadoutPatch.LogInterval.Value;
			bool flag = Object.op_Implicit((Object)(object)Run.instance);
			if (flag != wasRunning)
			{
				wasRunning = flag;
				nextLog = unscaledTime + 2f;
			}
			if (value > 0f && flag && unscaledTime >= nextLog)
			{
				nextLog = unscaledTime + value;
				Plugin.Log.LogInfo((object)LogLine());
			}
		}

		private void Build()
		{
			//IL_004a: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_0129: Unknown result type (might be due to invalid IL or missing references)
			canvas = UiFactory.CreateCanvas("LGP_PerfReadout", 99, interactive: false);
			RectTransform val = UiFactory.Panel(((Component)canvas).transform, "Panel");
			float value = PerfReadoutPatch.PanelX.Value;
			float num = 1f - PerfReadoutPatch.PanelY.Value;
			val.anchorMin = new Vector2(value, num);
			val.anchorMax = new Vector2(value, num);
			val.pivot = new Vector2(value, num);
			val.anchoredPosition = Vector2.zero;
			val.sizeDelta = new Vector2(290f, 56f + (float)Titles.Length * 22f);
			UiFactory.Row(((TMP_Text)UiFactory.Label((Transform)(object)val, "Title", "PERFORMANCE", GameSkin.TextKind.Header, 20f, (TextAlignmentOptions)513)).rectTransform, 14f, 262f, 14f, 28f);
			values = (HGTextMeshProUGUI[])(object)new HGTextMeshProUGUI[Titles.Length];
			for (int i = 0; i < Titles.Length; i++)
			{
				float y = 42f + (float)i * 22f;
				HGTextMeshProUGUI obj = UiFactory.Label((Transform)(object)val, "Label" + i, Titles[i], GameSkin.TextKind.Body, 16f, (TextAlignmentOptions)513);
				((Graphic)obj).color = GameSkin.QuietColor;
				UiFactory.Row(((TMP_Text)obj).rectTransform, 14f, 130f, y, 22f);
				values[i] = UiFactory.Label((Transform)(object)val, "Value" + i, string.Empty, GameSkin.TextKind.Header, 17f, (TextAlignmentOptions)516);
				UiFactory.Row(((TMP_Text)values[i]).rectTransform, 144f, 132f, y, 22f);
			}
		}

		private void WriteValues()
		{
			float num = Average();
			((TMP_Text)values[0]).text = $"{num * 1000f:0.0} ms";
			((TMP_Text)values[1]).text = ((num > 0f) ? (1f / num) : 0f).ToString("0", CultureInfo.InvariantCulture);
			((TMP_Text)values[2]).text = $"{PeakFrame() * 1000f:0.0} ms";
			((TMP_Text)values[3]).text = $"{runPeakFrame * 1000f:0.0} ms";
			((TMP_Text)values[4]).text = Monsters().ToString(CultureInfo.InvariantCulture);
			((TMP_Text)values[5]).text = HurtBox.readOnlyBullseyesList.Count.ToString(CultureInfo.InvariantCulture);
			((TMP_Text)values[6]).text = gcPerSecond.ToString("0.0", CultureInfo.InvariantCulture);
			((TMP_Text)values[7]).text = $"{GC.GetTotalMemory(forceFullCollection: false) / 1048576} MB";
		}

		private void RollPeaks(int second, float frame)
		{
			int num = secondPeaks.Length;
			if (lastSecond < 0)
			{
				lastSecond = second;
			}
			else if (second > lastSecond)
			{
				int num2 = second - lastSecond;
				if (num2 >= num)
				{
					Array.Clear(secondPeaks, 0, num);
				}
				else
				{
					for (int i = 1; i <= num2; i++)
					{
						secondPeaks[((lastSecond + i) % num + num) % num] = 0f;
					}
				}
				lastSecond = second;
			}
			int num3 = (second % num + num) % num;
			if (frame > secondPeaks[num3])
			{
				secondPeaks[num3] = frame;
			}
		}

		private float PeakFrame()
		{
			float num = 0f;
			for (int i = 0; i < secondPeaks.Length; i++)
			{
				if (secondPeaks[i] > num)
				{
					num = secondPeaks[i];
				}
			}
			return num;
		}

		private float Average()
		{
			if (sampleFill == 0)
			{
				return 0f;
			}
			float num = 0f;
			for (int i = 0; i < sampleFill; i++)
			{
				num += samples[i];
			}
			return num / (float)sampleFill;
		}

		private static int Monsters()
		{
			return TeamComponent.GetTeamMembers((TeamIndex)2).Count;
		}

		private string LogLine()
		{
			float num = Average();
			return string.Format(CultureInfo.InvariantCulture, "PERF stage {0} | frame avg {1:0.0} ms ({2:0} fps), peak {3:0.0} ms in {4:0} s, run peak {5:0.0} ms | bodies {6}, monsters {7}, models {8}, hurtboxes {9} | gc0 {10:0.0}/s, heap {11:0} MB", Clock(DpsMeterPatch.StageSeconds), num * 1000f, (num > 0f) ? (1f / num) : 0f, PeakFrame() * 1000f, 10f, runPeakFrame * 1000f, CharacterBody.readOnlyInstancesList.Count, Monsters(), InstanceTracker.GetInstancesList<CharacterModel>().Count, HurtBox.readOnlyBullseyesList.Count, gcPerSecond, GC.GetTotalMemory(forceFullCollection: false) / 1048576);
		}

		private static string Clock(float seconds)
		{
			int num = Mathf.Max(0, Mathf.FloorToInt(seconds));
			return (num / 60).ToString(CultureInfo.InvariantCulture) + ":" + (num % 60).ToString("00", CultureInfo.InvariantCulture);
		}
	}
	[BepInPlugin("com.tim.LateGamePerformance", "LateGamePerformance", "1.5.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.tim.LateGamePerformance";

		public const string Name = "LateGamePerformance";

		public const string Version = "1.5.0";

		internal static ManualLogSource Log;

		internal static ConfigFile Cfg;

		private Harmony coreHarmony;

		private void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = ((BaseUnityPlugin)this).Config;
			coreHarmony = new Harmony("com.tim.LateGamePerformance.core");
			ModMenu.Install(coreHarmony, ((Component)this).gameObject);
			int num = PatchRegistry.ApplyAll();
			StatPointsHud.Install(((Component)this).gameObject);
			DpsHud.Install(((Component)this).gameObject);
			StatPointsWindow.Install(((Component)this).gameObject);
			PerfHud.Install(((Component)this).gameObject);
			Log.LogInfo((object)string.Format("{0} {1}: {2} of {3} features active. Press {4} for the menu.", "LateGamePerformance", "1.5.0", num, PatchRegistry.Groups.Count, ModMenu.Hotkey.Value));
		}

		private void OnDestroy()
		{
			ModMenu.Close();
			PatchRegistry.DisableAll();
			Harmony obj = coreHarmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	internal sealed class StatPointsHud : MonoBehaviour
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Open;
		}

		private const float BadgeSize = 74f;

		private static ConfigEntry<bool> showBadge;

		private static ConfigEntry<KeyboardShortcut> openKey;

		private static ConfigEntry<float> badgeX;

		private static ConfigEntry<float> badgeY;

		private Canvas canvas;

		private RectTransform badge;

		private HGTextMeshProUGUI count;

		private HGTextMeshProUGUI word;

		private Image backing;

		internal static StatPointsHud Instance { get; private set; }

		internal static void Install(GameObject host)
		{
			//IL_0038: 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_0083: Expected O, but got Unknown
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			showBadge = Plugin.Cfg.Bind<bool>("StatPoints", "ShowBadge", true, "Show a badge on screen while you have points to spend.");
			openKey = Plugin.Cfg.Bind<KeyboardShortcut>("StatPoints", "OpenKey", new KeyboardShortcut((KeyCode)284, Array.Empty<KeyCode>()), "Key that opens the stat points window.");
			badgeX = Plugin.Cfg.Bind<float>("StatPoints", "BadgeX", 0.028f, new ConfigDescription("Badge position across the screen, 0 is left and 1 is right.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			badgeY = Plugin.Cfg.Bind<float>("StatPoints", "BadgeY", 0.4f, new ConfigDescription("Badge position down the screen, 0 is top and 1 is bottom.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			Instance = host.AddComponent<StatPointsHud>();
		}

		private void Update()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			if (openKey != null)
			{
				KeyboardShortcut value = openKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() && !ModMenu.IsOpen)
				{
					StatPointsWindow.Toggle();
					return;
				}
			}
			int num = Available();
			if (showBadge == null || !showBadge.Value || !StatPointsPatch.CanSpend || num <= 0 || !Object.op_Implicit((Object)(object)Run.instance) || ModMenu.IsOpen || StatPointsWindow.IsOpen)
			{
				UiFactory.SetVisible(canvas, visible: false);
				return;
			}
			GameSkin.Refresh();
			if (GameSkin.Ready)
			{
				if ((Object)(object)canvas == (Object)null)
				{
					Build();
				}
				UiFactory.SetVisible(canvas, visible: true);
				((TMP_Text)count).text = num.ToString();
				((TMP_Text)word).text = ((num == 1) ? "point" : "points");
				float num2 = 0.75f + 0.25f * Mathf.Sin(Time.unscaledTime * 3f);
				Color headerColor = GameSkin.HeaderColor;
				((Graphic)backing).color = new Color(headerColor.r, headerColor.g, headerColor.b, 0.2f * num2);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)canvas != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)canvas).gameObject);
			}
		}

		private static int Available()
		{
			if (!StatPointsPatch.TryGetLocal(out var tracker, out var _))
			{
				return 0;
			}
			return tracker.AvailablePoints();
		}

		private void Build()
		{
			//IL_0054: 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_0078: 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_00a2: 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_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: 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_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			canvas = UiFactory.CreateCanvas("LGP_StatBadge", 98, interactive: true);
			badge = UiFactory.Panel(((Component)canvas).transform, "Badge");
			float value = badgeX.Value;
			float num = 1f - badgeY.Value;
			badge.anchorMin = new Vector2(value, num);
			badge.anchorMax = new Vector2(value, num);
			badge.pivot = new Vector2(value, num);
			badge.anchoredPosition = Vector2.zero;
			badge.sizeDelta = new Vector2(74f, 92f);
			backing = UiFactory.Fill((Transform)(object)badge, "Pulse", Color.clear);
			UiFactory.Stretch(((Graphic)backing).rectTransform, 3f, 3f);
			GameObject val = new GameObject("Open", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)badge, false);
			UiFactory.Stretch(component);
			Image component2 = val.GetComponent<Image>();
			((Graphic)component2).color = new Color(0f, 0f, 0f, 0.01f);
			Button obj = val.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)component2;
			ButtonClickedEvent onClick = obj.onClick;
			object obj2 = <>O.<0>__Open;
			if (obj2 == null)
			{
				UnityAction val2 = StatPointsWindow.Open;
				<>O.<0>__Open = val2;
				obj2 = (object)val2;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj2);
			count = UiFactory.Label((Transform)(object)badge, "Count", "0", GameSkin.TextKind.Header, 30f, (TextAlignmentOptions)514);
			UiFactory.Row(((TMP_Text)count).rectTransform, 0f, 74f, 6f, 34f);
			word = UiFactory.Label((Transform)(object)badge, "Word", "points", GameSkin.TextKind.Body, 14f, (TextAlignmentOptions)514);
			((Graphic)word).color = GameSkin.QuietColor;
			UiFactory.Row(((TMP_Text)word).rectTransform, 0f, 74f, 40f, 18f);
			RectTransform parent = badge;
			KeyboardShortcut value2 = openKey.Value;
			HGTextMeshProUGUI obj3 = UiFactory.Label((Transform)(object)parent, "Hint", ((object)((KeyboardShortcut)(ref value2)).MainKey/*cast due to .constrained prefix*/).ToString(), GameSkin.TextKind.Body, 13f, (TextAlignmentOptions)514);
			((Graphic)obj3).color = GameSkin.QuietColor;
			UiFactory.Row(((TMP_Text)obj3).rectTransform, 0f, 74f, 60f, 18f);
		}
	}
	internal sealed class StatPointsWindow : MonoBehaviour
	{
		private const float WindowWidth = 520f;

		private const float Pad = 18f;

		private Canvas canvas;

		private StatPointsPanel panel;

		private readonly CursorHold cursor = new CursorHold();

		internal static StatPointsWindow Instance { get; private set; }

		internal static bool IsOpen { get; private set; }

		internal static void Install(GameObject host)
		{
			Instance = host.AddComponent<StatPointsWindow>();
		}

		internal static void Toggle()
		{
			Instance?.SetOpen(!IsOpen);
		}

		internal static void Open()
		{
			Instance?.SetOpen(open: true);
		}

		internal static void Close()
		{
			Instance?.SetOpen(open: false);
		}

		private void Update()
		{
			if (!IsOpen)
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)27) || !Object.op_Implicit((Object)(object)Run.instance) || ModMenu.IsOpen)
			{
				SetOpen(open: false);
				return;
			}
			cursor.Set(wanted: true);
			GameSkin.Refresh();
			if (GameSkin.Ready)
			{
				if ((Object)(object)canvas == (Object)null)
				{
					Build();
				}
				UiFactory.SetVisible(canvas, visible: true);
				panel.Refresh();
			}
		}

		private void OnDisable()
		{
			SetOpen(open: false);
		}

		private void OnDestroy()
		{
			if ((Object)(object)canvas != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)canvas).gameObject);
			}
		}

		private void SetOpen(bool open)
		{
			if (open != IsOpen)
			{
				IsOpen = open;
				UiFactory.SetVisible(canvas, open);
				if (!open)
				{
					cursor.Release();
				}
			}
		}

		private void Build()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			canvas = UiFactory.CreateCanvas("LGP_StatPoints", 190, interactive: true);
			Image obj = UiFactory.Fill(((Component)canvas).transform, "Dim", new Color(0f, 0f, 0f, 0.55f));
			UiFactory.Stretch(((Graphic)obj).rectTransform);
			((Graphic)obj).raycastTarget = true;
			RectTransform obj2 = UiFactory.Panel(((Component)canvas).transform, "Window", GameSkin.PanelKind.Main, opaque: true);
			obj2.anchorMin = new Vector2(0.5f, 0.5f);
			obj2.anchorMax = new Vector2(0.5f, 0.5f);
			obj2.pivot = new Vector2(0.5f, 0.5f);
			obj2.anchoredPosition = Vector2.zero;
			obj2.sizeDelta = new Vector2(520f, 480f);
			RectTransform val = UiFactory.Vertical((Transform)(object)obj2, "Body", 10f, 18);
			UiFactory.Stretch(val);
			RectTransform parent = UiFactory.Horizontal((Transform)(object)val, "TitleBar", 10f, 34f);
			UiFactory.Size((Component)(object)UiFactory.Label((Transform)(object)parent, "Title", "LEVEL UP", GameSkin.TextKind.Header, 26f, (TextAlignmentOptions)513), 340f, 32f);
			UiFactory.Size((Component)(object)UiFactory.Button((Transform)(object)parent, "Close", "Close", delegate
			{
				SetOpen(open: false);
			}), 110f, 32f);
			panel = new StatPointsPanel((Transform)(object)val);
		}
	}
}
namespace LateGamePerformance.Ui
{
	internal sealed class CursorHold
	{
		private readonly List<MPEventSystem> linked = new List<MPEventSystem>();

		internal void Set(bool wanted)
		{
			if (!wanted)
			{
				Release();
				return;
			}
			for (int num = linked.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)linked[num] == (Object)null)
				{
					linked.RemoveAt(num);
				}
			}
			ReadOnlyCollection<MPEventSystem> readOnlyInstancesList = MPEventSystem.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				MPEventSystem val = readOnlyInstancesList[i];
				if (!((Object)(object)val == (Object)null) && !linked.Contains(val))
				{
					int cursorOpenerCount = val.cursorOpenerCount;
					val.cursorOpenerCount = cursorOpenerCount + 1;
					cursorOpenerCount = val.cursorOpenerForGamepadCount;
					val.cursorOpenerForGamepadCount = cursorOpenerCount + 1;
					linked.Add(val);
				}
			}
		}

		internal void Release()
		{
			for (int i = 0; i < linked.Count; i++)
			{
				MPEventSystem val = linked[i];
				if (!((Object)(object)val == (Object)null))
				{
					int cursorOpenerCount = val.cursorOpenerCount;
					val.cursorOpenerCount = cursorOpenerCount - 1;
					cursorOpenerCount = val.cursorOpenerForGamepadCount;
					val.cursorOpenerForGamepadCount = cursorOpenerCount - 1;
				}
			}
			linked.Clear();
		}
	}
	internal static class GameSkin
	{
		internal enum PanelKind
		{
			Main,
			Header,
			Detail
		}

		internal enum TextKind
		{
			Body,
			Header,
			Detail
		}

		private static UISkinData data;

		private static bool searched;

		internal static UISkinData Data
		{
			get
			{
				if ((Object)(object)data == (Object)null && !searched)
				{
					searched = true;
					data = Find();
					if ((Object)(object)data == (Object)null)
					{
						Plugin.Log.LogWarning((object)"No UISkinData found yet. Menus fall back to plain colors until one loads.");
					}
				}
				return data;
			}
		}

		internal static bool Ready => (Object)(object)Data != (Object)null;

		internal static float ButtonHeight
		{
			get
			{
				if (!((Object)(object)Data != (Object)null))
				{
					return 32f;
				}
				return Mathf.Max(28f, Data.buttonStyle.recommendedHeight);
			}
		}

		internal static Color HeaderColor
		{
			get
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)Data != (Object)null))
				{
					return new Color(1f, 0.78f, 0.33f);
				}
				return Data.headerTextStyle.color;
			}
		}

		internal static Color BodyColor
		{
			get
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)Data != (Object)null))
				{
					return Color.white;
				}
				return Data.bodyTextStyle.color;
			}
		}

		internal static Color DetailColor
		{
			get
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)Data != (Object)null))
				{
					return new Color(0.6f, 0.64f, 0.71f);
				}
				return Data.detailTextStyle.color;
			}
		}

		internal static Color QuietColor
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: 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)
				//IL_0018: 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)
				Color bodyColor = BodyColor;
				return new Color(bodyColor.r, bodyColor.g, bodyColor.b, bodyColor.a * 0.55f);
			}
		}

		internal static void Refresh()
		{
			if ((Object)(object)data == (Object)null)
			{
				searched = false;
			}
		}

		private static UISkinData Find()
		{
			UISkinData val = null;
			int num = 0;
			List<UISkinData> list = new List<UISkinData>(Resources.FindObjectsOfTypeAll<UISkinData>());
			BaseSkinController[] array = Resources.FindObjectsOfTypeAll<BaseSkinController>();
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] != (Object)null && (Object)(object)array[i].skinData != (Object)null && !list.Contains(array[i].skinData))
				{
					list.Add(array[i].skinData);
				}
			}
			for (int j = 0; j < list.Count; j++)
			{
				int num2 = Score(list[j]);
				if (num2 > num)
				{
					num = num2;
					val = list[j];
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				Plugin.Log.LogInfo((object)$"UI skin: '{((Object)val).name}' out of {list.Count} candidates, score {num}.");
			}
			return val;
		}

		private static int Score(UISkinData skin)
		{
			if ((Object)(object)skin == (Object)null)
			{
				return 0;
			}
			int num = 1;
			if ((Object)(object)skin.bodyTextStyle.font != (Object)null)
			{
				num += 4;
			}
			if ((Object)(object)skin.headerTextStyle.font != (Object)null)
			{
				num += 2;
			}
			if (skin.bodyTextStyle.color.a > 0.5f)
			{
				num += 4;
			}
			if (skin.headerTextStyle.color.a > 0.5f)
			{
				num += 2;
			}
			if ((Object)(object)skin.mainPanelStyle.sprite != (Object)null)
			{
				num += 4;
			}
			if (skin.mainPanelStyle.color.a > 0.2f)
			{
				num += 2;
			}
			if ((Object)(object)skin.buttonStyle.sprite != (Object)null)
			{
				num += 2;
			}
			return num;
		}

		internal static void ApplyPanel(Image image, PanelKind kind)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			UISkinData val = Data;
			if (!((Object)(object)val == (Object)null) && !((Object)(object)image == (Object)null))
			{
				switch (kind)
				{
				case PanelKind.Header:
					((PanelStyle)(ref val.headerPanelStyle)).Apply(image);
					break;
				case PanelKind.Detail:
					((PanelStyle)(ref val.detailPanelStyle)).Apply(image);
					break;
				default:
					((PanelStyle)(ref val.mainPanelStyle)).Apply(image);
					break;
				}
				if ((Object)(object)image.sprite != (Object)null)
				{
					image.type = (Type)(!(image.sprite.border == Vector4.zero));
				}
			}
		}

		internal static void ApplyText(TextMeshProUGUI label, TextKind kind, bool useSkinAlignment = false)
		{
			UISkinData val = Data;
			if (!((Object)(object)val == (Object)null) && !((Object)(object)label == (Object)null))
			{
				switch (kind)
				{
				case TextKind.Header:
					((TextStyle)(ref val.headerTextStyle)).Apply(label, useSkinAlignment);
					break;
				case TextKind.Detail:
					((TextStyle)(ref val.detailTextStyle)).Apply(label, useSkinAlignment);
					break;
				default:
					((TextStyle)(ref val.bodyTextStyle)).Apply(label, useSkinAlignment);
					break;
				}
			}
		}

		internal static void ApplyButton(Button button, Image image, TextMeshProUGUI label)
		{
			//IL_0011: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			UISkinData val = Data;
			if (!((Object)(object)val == (Object)null))
			{
				ButtonStyle buttonStyle = val.buttonStyle;
				ColorBlock defaultColorBlock = ColorBlock.defaultColorBlock;
				((ColorBlock)(ref defaultColorBlock)).normalColor = new Color(1f, 1f, 1f, 0.1f);
				((ColorBlock)(ref defaultColorBlock)).highlightedColor = new Color(1f, 1f, 1f, 0.26f);
				((ColorBlock)(ref defaultColorBlock)).pressedColor = new Color(1f, 1f, 1f, 0.4f);
				((ColorBlock)(ref defaultColorBlock)).selectedColor = new Color(1f, 1f, 1f, 0.16f);
				((ColorBlock)(ref defaultColorBlock)).disabledColor = new Color(1f, 1f, 1f, 0.04f);
				((ColorBlock)(ref defaultColorBlock)).fadeDuration = 0.08f;
				if ((Object)(object)button != (Object)null)
				{
					((Selectable)button).colors = defaultColorBlock;
				}
				if ((Object)(object)image != (Object)null)
				{
					image.sprite = null;
					((Graphic)image).material = null;
					((Graphic)image).color = Color.white;
				}
				if ((Object)(object)label != (Object)null)
				{
					((TextStyle)(ref buttonStyle.interactableTextStyle)).Apply(label, false);
				}
			}
		}

		internal static Color PanelColor(PanelKind kind)
		{
			//IL_0023: 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_0045: 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)
			UISkinData val = Data;
			if ((Object)(object)val == (Object)null)
			{
				return new Color(0.06f, 0.07f, 0.09f, 1f);
			}
			return (Color)(kind switch
			{
				PanelKind.Header => val.headerPanelStyle.color, 
				PanelKind.Detail => val.detailPanelStyle.color, 
				_ => val.mainPanelStyle.color, 
			});
		}
	}
	internal sealed class SettingRow
	{
		private readonly ConfigEntryBase entry;

		private readonly Button toggleButton;

		private readonly HGTextMeshProUGUI toggleLabel;

		private readonly Slider slider;

		private readonly HGTextMeshProUGUI readout;

		private bool writing;

		internal ConfigEntryBase Entry => entry;

		internal static SettingRow Create(Transform parent, ConfigEntryBase entry, Action<ConfigEntryBase> onKeyBindRequest)
		{
			return new SettingRow(parent, entry, onKeyBindRequest);
		}

		private SettingRow(Transform parent, ConfigEntryBase entry, Action<ConfigEntryBase> onKeyBindRequest)
		{
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			this.entry = entry;
			RectTransform parent2 = UiFactory.Vertical(parent, "Setting_" + entry.Definition.Key, 2f);
			RectTransform parent3 = UiFactory.Horizontal((Transform)(object)parent2, "Line", 10f, 30f);
			UiFactory.Size((Component)(object)UiFactory.Label((Transform)(object)parent3, "Name", Spaced(entry.Definition.Key), GameSkin.TextKind.Body, 18f, (TextAlignmentOptions)513), 230f, 28f);
			Type settingType = entry.SettingType;
			if (settingType == typeof(bool))
			{
				toggleButton = UiFactory.Button((Transform)(object)parent3, "Toggle", string.Empty, Flip);
				toggleLabel = ((Component)toggleButton).GetComponentInChildren<HGTextMeshProUGUI>();
				UiFactory.Size((Component)(object)toggleButton, 78f, 28f);
			}
			else if (settingType == typeof(float) || settingType == typeof(int))
			{
				slider = MakeSlider((Transform)(object)parent3, settingType == typeof(int));
				readout = UiFactory.Label((Transform)(object)parent3, "Value", string.Empty, GameSkin.TextKind.Header, 18f, (TextAlignmentOptions)516);
				UiFactory.Size((Component)(object)readout, 74f, 28f);
			}
			else if (settingType == typeof(KeyboardShortcut))
			{
				toggleButton = UiFactory.Button((Transform)(object)parent3, "Bind", string.Empty, delegate
				{
					onKeyBindRequest?.Invoke(entry);
				});
				toggleLabel = ((Component)toggleButton).GetComponentInChildren<HGTextMeshProUGUI>();
				UiFactory.Size((Component)(object)toggleButton, 150f, 28f);
			}
			else if (settingType.IsEnum)
			{
				toggleButton = UiFactory.Button((Transform)(object)parent3, "Cycle", string.Empty, CycleEnum);
				toggleLabel = ((Component)toggleButton).GetComponentInChildren<HGTextMeshProUGUI>();
				UiFactory.Size((Component)(object)toggleButton, 170f, 28f);
			}
			else
			{
				readout = UiFactory.Label((Transform)(object)parent3, "Value", entry.GetSerializedValue(), GameSkin.TextKind.Body, 17f, (TextAlignmentOptions)513);
				UiFactory.Size((Component)(object)readout, 200f, 28f);
			}
			ConfigDescription description = entry.Description;
			string text = ((description != null) ? description.Description : null);
			if (!string.IsNullOrEmpty(text))
			{
				HGTextMeshProUGUI obj = UiFactory.Label((Transform)(object)parent2, "Help", text, GameSkin.TextKind.Body, 15f, (TextAlignmentOptions)257);
				((Graphic)obj).color = GameSkin.QuietColor;
				((TMP_Text)obj).enableWordWrapping = true;
				((TMP_Text)obj).overflowMode = (TextOverflowModes)0;
				UiFactory.Size((Component)(object)obj, 0f, 34f);
			}
			Refresh();
		}

		private Slider MakeSlider(Transform parent, bool whole)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: 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_0128: 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)
			GameObject val = new GameObject("Slider", new Type[1] { typeof(RectTransform) });
			((Transform)val.GetComponent<RectTransform>()).SetParent(parent, false);
			Slider val2 = val.AddComponent<Slider>();
			UiFactory.Size((Component)(object)val2, 250f, 24f);
			UiFactory.Stretch(((Graphic)UiFactory.Fill(val.transform, "Track", new Color(1f, 1f, 1f, 0.14f))).rectTransform, 0f, 9f);
			RectTransform component = new GameObject("FillArea", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component).SetParent(val.transform, false);
			UiFactory.Stretch(component, 0f, 9f);
			Image val3 = UiFactory.Fill((Transform)(object)component, "Fill", GameSkin.HeaderColor);
			UiFactory.Stretch(((Graphic)val3).rectTransform);
			RectTransform component2 = new GameObject("HandleArea", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component2).SetParent(val.transform, false);
			UiFactory.Stretch(component2);
			Image val4 = UiFactory.Fill((Transform)(object)component2, "Handle", GameSkin.HeaderColor);
			((Graphic)val4).raycastTarget = true;
			((Graphic)val4).rectTransform.sizeDelta = new Vector2(12f, 0f);
			val2.fillRect = ((Graphic)val3).rectTransform;
			val2.handleRect = ((Graphic)val4).rectTransform;
			((Selectable)val2).targetGraphic = (Graphic)(object)val4;
			val2.wholeNumbers = whole;
			GetRange(out var min, out var max);
			val2.minValue = min;
			val2.maxValue = max;
			((UnityEvent<float>)(object)val2.onValueChanged).AddListener((UnityAction<float>)OnSlider);
			return val2;
		}

		private void OnSlider(float value)
		{
			if (!writing)
			{
				if (entry.SettingType == typeof(int))
				{
					entry.BoxedValue = Mathf.RoundToInt(value);
				}
				else
				{
					entry.BoxedValue = value;
				}
				WriteReadout();
			}
		}

		private void Flip()
		{
			entry.BoxedValue = !(bool)entry.BoxedValue;
			Refresh();
		}

		private void CycleEnum()
		{
			Type settingType = entry.SettingType;
			string[] names = Enum.GetNames(settingType);
			string value = entry.BoxedValue.ToString();
			int num = Array.IndexOf(names, value);
			entry.BoxedValue = Enum.Parse(settingType, names[(num + 1) % names.Length]);
			Refresh();
		}

		private void GetRange(out float min, out float max)
		{
			ConfigDescription description = entry.Description;
			AcceptableValueBase val = ((description != null) ? description.AcceptableValues : null);
			if (!(val is AcceptableValueRange<float> val2))
			{
				if (val is AcceptableValueRange<int> val3)
				{
					min = val3.MinValue;
					max = val3.MaxValue;
				}
				else
				{
					min = 0f;
					max = ((entry.SettingType == typeof(int)) ? 100f : 10f);
				}
			}
			else
			{
				min = val2.MinValue;
				max = val2.MaxValue;
			}
		}

		internal void Refresh()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			writing = true;
			try
			{
				if (entry.SettingType == typeof(bool) && (Object)(object)toggleLabel != (Object)null)
				{
					bool flag = (bool)entry.BoxedValue;
					((TMP_Text)toggleLabel).text = (flag ? "ON" : "OFF");
					((Graphic)toggleLabel).color = (flag ? GameSkin.HeaderColor : GameSkin.QuietColor);
				}
				else if (entry.SettingType == typeof(KeyboardShortcut) && (Object)(object)toggleLabel != (Object)null)
				{
					((TMP_Text)toggleLabel).text = entry.BoxedValue.ToString();
				}
				else if (entry.SettingType.IsEnum && (Object)(object)toggleLabel != (Object)null)
				{
					((TMP_Text)toggleLabel).text = entry.BoxedValue.ToString();
				}
				else if ((Object)(object)slider != (Object)null)
				{
					slider.value = Convert.ToSingle(entry.BoxedValue, CultureInfo.InvariantCulture);
					WriteReadout();
				}
			}
			finally
			{
				writing = false;
			}
		}

		internal void SetBindPrompt(bool waiting)
		{
			if ((Object)(object)toggleLabel != (Object)null && entry.SettingType == typeof(KeyboardShortcut))
			{
				((TMP_Text)toggleLabel).text = (waiting ? "press a key" : entry.BoxedValue.ToString());
			}
		}

		private void WriteReadout()
		{
			if (!((Object)(object)readout == (Object)null))
			{
				((TMP_Text)readout).text = ((entry.SettingType == typeof(int)) ? ((int)entry.BoxedValue).ToString(CultureInfo.InvariantCulture) : ((float)entry.BoxedValue).ToString("0.###", CultureInfo.InvariantCulture));
			}
		}

		private static string Spaced(string key)
		{
			StringBuilder stringBuilder = new StringBuilder(key.Length + 6);
			for (int i = 0; i < key.Length; i++)
			{
				char c = key[i];
				if (i > 0 && char.IsUpper(c) && !char.IsUpper(key[i - 1]))
				{
					stringBuilder.Append(' ');
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
				else
				{
					stringBuilder.Append((i == 0) ? c : char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}
	}
	internal sealed class StatPointsPanel
	{
		private sealed class StatLine
		{
			internal StatPointsPatch.Stat stat;

			internal HGTextMeshProUGUI value;

			internal HGTextMeshProUGUI spent;

			internal Button minus;

			internal Button plus;
		}

		private readonly HGTextMeshProUGUI heading;

		private readonly HGTextMeshProUGUI note;

		private readonly List<StatLine> lines = new List<StatLine>();

		private readonly Button reset;

		internal StatPointsPanel(Transform parent)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			RectTransform parent2 = UiFactory.Vertical(parent, "StatPoints", 4f);
			heading = UiFactory.Label((Transform)(object)parent2, "Heading", string.Empty, GameSkin.TextKind.Header, 21f, (TextAlignmentOptions)513);
			UiFactory.Size((Component)(object)heading, 0f, 28f);
			note = UiFactory.Label((Transform)(object)parent2, "Note", string.Empty, GameSkin.TextKind.Body, 16f, (TextAlignmentOptions)513);
			((Graphic)note).color = GameSkin.QuietColor;
			UiFactory.Size((Component)(object)note, 0f, 24f);
			StatPointsPatch.Stat[] allStats = StatPointsPatch.AllStats;
			for (int i = 0; i < allStats.Length; i++)
			{
				StatPointsPatch.Stat stat = allStats[i];
				RectTransform parent3 = UiFactory.Horizontal((Transform)(object)parent2, "Stat" + stat, 8f, 32f);
				StatPointsPatch.Stat captured = stat;
				UiFactory.Size((Component)(object)UiFactory.Label((Transform)(object)parent3, "Name", StatPointsPatch.Describe(stat), GameSkin.TextKind.Body, 18f, (TextAlignmentOptions)513), 190f, 30f);
				HGTextMeshProUGUI val = UiFactory.Label((Transform)(object)parent3, "Value", string.Empty, GameSkin.TextKind.Header, 18f, (TextAlignmentOptions)516);
				UiFactory.Size((Component)(object)val, 90f, 30f);
				HGTextMeshProUGUI val2 = UiFactory.Label((Transform)(object)parent3, "Spent", string.Empty, GameSkin.TextKind.Body, 16f, (TextAlignmentOptions)516);
				((Graphic)val2).color = GameSkin.QuietColor;
				UiFactory.Size((Component)(object)val2, 56f, 30f);
				Button val3 = UiFactory.Button((Transform)(object)parent3, "Minus", "-", delegate
				{
					StatPointsPatch.RefundLocal(captured);
				});
				UiFactory.Size((Component)(object)val3, 40f, 30f);
				Button val4 = UiFactory.Button((Transform)(object)parent3, "Plus", "+", delegate
				{
					StatPointsPatch.SpendLocal(captured);
				});
				UiFactory.Size((Component)(object)val4, 40f, 30f);
				lines.Add(new StatLine
				{
					stat = stat,
					value = val,
					spent = val2,
					minus = val3,
					plus = val4
				});
			}
			reset = UiFactory.Button((Transform)(object)parent2, "Reset", "Take every point back", StatPointsPatch.RefundAllLocal);
			UiFactory.Size((Component)(object)reset, 260f, 32f);
			Refresh();
		}

		internal void Refresh()
		{
			if (!StatPointsPatch.TryGetLocal(out var tracker, out var body))
			{
				((TMP_Text)heading).text = "Start a run to spend points.";
				((TMP_Text)note).text = string.Empty;
				for (int i = 0; i < lines.Count; i++)
				{
					((TMP_Text)lines[i].value).text = "-";
					((TMP_Text)lines[i].spent).text = string.Empty;
					((Selectable)lines[i].minus).interactable = false;
					((Selectable)lines[i].plus).interactable = false;
				}
				((Selectable)reset).interactable = false;
				return;
			}
			bool canSpend = StatPointsPatch.CanSpend;
			int num = tracker.AvailablePoints();
			if (canSpend)
			{
				((TMP_Text)heading).text = ((num == 1) ? "1 point to spend" : $"{num} points to spend");
				((TMP_Text)note).text = $"Character level {Mathf.FloorToInt(body.level)}, {tracker.EarnedPoints()} points earned in total.";
			}
			else
			{
				((TMP_Text)heading).text = "Points count on the host only";
				((TMP_Text)note).text = "Another machine runs this game, so a point spent here would not reach your character.";
			}
			for (int j = 0; j < lines.Count; j++)
			{
				StatLine statLine = lines[j];
				int spent = tracker.GetSpent(statLine.stat);
				((TMP_Text)statLine.value).text = StatPointsPatch.CurrentValue(body, statLine.stat);
				((TMP_Text)statLine.spent).text = ((spent > 0) ? ("+" + spent.ToString(CultureInfo.InvariantCulture)) : string.Empty);
				((Selectable)statLine.minus).interactable = canSpend && spent > 0;
				((Selectable)statLine.plus).interactable = canSpend && num > 0;
			}
			((Selectable)reset).interactable = canSpend && tracker.TotalSpent() > 0;
		}
	}
	internal static class UiFactory
	{
		private const float ReferenceWidth = 1920f;

		private const float ReferenceHeight = 1080f;

		internal static Canvas CreateCanvas(string name, int sortOrder, bool interactive)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler)
			});
			Object.DontDestroyOnLoad((Object)(object)val);
			Canvas component = val.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = sortOrder;
			CanvasScaler component2 = val.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1920f, 1080f);
			component2.screenMatchMode = (ScreenMatchMode)0;
			component2.matchWidthOrHeight = 1f;
			if (interactive)
			{
				val.AddComponent<GraphicRaycaster>();
			}
			return component;
		}

		internal static void SetVisible(Canvas canvas, bool visible)
		{
			if (!((Object)(object)canvas == (Object)null) && ((Behaviour)canvas).enabled != visible)
			{
				((Behaviour)canvas).enabled = visible;
				GraphicRaycaster component = ((Component)canvas).GetComponent<GraphicRaycaster>();
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = visible;
				}
			}
		}

		internal static RectTransform Panel(Transform parent, string name, GameSkin.PanelKind kind = GameSkin.PanelKind.Main, bool opaque = false)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_005b: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_008a: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			if (!opaque)
			{
				GameSkin.ApplyPanel(val.GetComponent<Image>(), kind);
				return component;
			}
			Image component2 = val.GetComponent<Image>();
			Color val2 = GameSkin.PanelColor(kind);
			((Graphic)component2).color = new Color(val2.r * 0.5f, val2.g * 0.5f, val2.b * 0.5f, 0.97f);
			GameObject val3 = new GameObject("Skin", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			RectTransform component3 = val3.GetComponent<RectTransform>();
			((Transform)component3).SetParent((Transform)(object)component, false);
			Stretch(component3);
			Image component4 = val3.GetComponent<Image>();
			((Graphic)component4).raycastTarget = false;
			GameSkin.ApplyPanel(component4, kind);
			return component;
		}

		internal static Image Fill(Transform parent, string name, Color color)
		{
			//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_0046: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			((Transform)val.GetComponent<RectTransform>()).SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = color;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		internal static HGTextMeshProUGUI Label(Transform parent, string name, string text, GameSkin.TextKind kind, float fontSize, TextAlignmentOptions alignment)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			((Transform)val.GetComponent<RectTransform>()).SetParent(parent, false);
			HGTextMeshProUGUI obj = val.AddComponent<HGTextMeshProUGUI>();
			GameSkin.ApplyText((TextMeshProUGUI)(object)obj, kind);
			((TMP_Text)obj).text = text;
			((TMP_Text)obj).fontSize = fontSize;
			((TMP_Text)obj).alignment = alignment;
			((TMP_Text)obj).enableWordWrapping = false;
			((TMP_Text)obj).overflowMode = (TextOverflowModes)0;
			((Graphic)obj).raycastTarget = false;
			return obj;
		}

		internal static Button Button(Transform parent, string name, string text, Action onClick)
		{
			//IL_003b: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			((Transform)val.GetComponent<RectTransform>()).SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			Button val2 = val.AddComponent<Button>();
			((Selectable)val2).targetGraphic = (Graphic)(object)component;
			HGTextMeshProUGUI val3 = Label(val.transform, "Text", text, GameSkin.TextKind.Body, 20f, (TextAlignmentOptions)514);
			Stretch(((TMP_Text)val3).rectTransform, 10f, 2f);
			GameSkin.ApplyButton(val2, component, (TextMeshProUGUI)(object)val3);
			if (onClick != null)
			{
				((UnityEvent)val2.onClick).AddListener((UnityAction)delegate
				{
					onClick();
				});
			}
			return val2;
		}

		internal static RectTransform Vertical(Transform parent, string name, float spacing, int pad = 0)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			VerticalLayoutGroup obj = val.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = spacing;
			((LayoutGroup)obj).padding = new RectOffset(pad, pad, pad, pad);
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			return component;
		}

		internal static RectTransform Horizontal(Transform parent, string name, float spacing, float height)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = spacing;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = true;
			((LayoutGroup)obj).childAlignment = (TextAnchor)3;
			if (height > 0f)
			{
				val.AddComponent<LayoutElement>().minHeight = height;
			}
			return component;
		}

		internal static LayoutElement Size(Component target, float width, float height = -1f)
		{
			LayoutElement val = target.gameObject.GetComponent<LayoutElement>() ?? target.gameObject.AddComponent<LayoutElement>();
			if (width > 0f)
			{
				val.minWidth = width;
				val.preferredWidth = width;
			}
			if (height > 0f)
			{
				val.minHeight = height;
				val.preferredHeight = height;
			}
			return val;
		}

		internal static RectTransform Scroll(Transform parent, string name, out ScrollRect scroll)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_008c: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: 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_0130: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			scroll = val.AddComponent<ScrollRect>();
			scroll.horizontal = false;
			scroll.movementType = (MovementType)2;
			scroll.scrollSensitivity = 28f;
			GameObject val2 = new GameObject("Viewport", new Type[4]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(RectMask2D)
			});
			RectTransform component2 = val2.GetComponent<RectTransform>();
			((Transform)component2).SetParent((Transform)(object)component, false);
			Stretch(component2);
			((Graphic)val2.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.01f);
			RectTransform val3 = Vertical((Transform)(object)component2, "Content", 4f);
			val3.anchorMin = new Vector2(0f, 1f);
			val3.anchorMax = new Vector2(1f, 1f);
			val3.pivot = new Vector2(0.5f, 1f);
			val3.anchoredPosition = Vector2.zero;
			val3.sizeDelta = Vector2.zero;
			((Component)val3).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			scroll.viewport = component2;
			scroll.content = val3;
			return val3;
		}

		internal static void Stretch(RectTransform rect, float padX = 0f, float padY = 0f)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
			rect.offsetMin = new Vector2(padX, padY);
			rect.offsetMax = new Vector2(0f - padX, 0f - padY);
		}

		internal static void Place(RectTransform rect, Vector2 anchor, Vector2 pivot, Vector2 position, Vector2 size)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = anchor;
			rect.anchorMax = anchor;
			rect.pivot = pivot;
			rect.anchoredPosition = position;
			rect.sizeDelta = size;
		}

		internal static void Row(RectTransform rect, float x, float width, float y, float height)
		{
			//IL_000b: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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)
			rect.anchorMin = new Vector2(0f, 1f);
			rect.anchorMax = new Vector2(0f, 1f);
			rect.pivot = new Vector2(0f, 1f);
			rect.anchoredPosition = new Vector2(x, 0f - y);
			rect.sizeDelta = new Vector2(width, height);
		}
	}
}
namespace LateGamePerformance.Patches
{
	internal static class AutoSprintPatch
	{
		private static ConfigEntry<float> holdOffSeconds;

		private static ConfigEntry<bool> holdToWalk;

		private const int SprintActionId = 18;

		private static ConfigEntry<float> moveThreshold;

		private static readonly Dictionary<CharacterBody, float> suppressedUntil = new Dictionary<CharacterBody, float>();

		internal static void Apply(Harmony harmony)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			holdToWalk = Plugin.Cfg.Bind<bool>("AutoSprint", "HoldSprintKeyToWalk", true, "Reverses the sprint key. You sprint by default. Hold the sprint key to walk.");
			holdOffSeconds = Plugin.Cfg.Bind<float>("AutoSprint", "HoldOffSeconds", 0.4f, new ConfigDescription("Pause before sprint resumes after a skill that cancels sprint.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			moveThreshold = Plugin.Cfg.Bind<float>("AutoSprint", "MoveThreshold", 0.5f, new ConfigDescription("Minimum move input before sprint engages.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerCharacterMasterController), "PollButtonInput", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AutoSprintPatch), "PollButtonInputPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(GenericSkill), "OnExecute", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AutoSprintPatch), "SkillExecutePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Run.onRunDestroyGlobal -= OnRunDestroy;
			Run.onRunDestroyGlobal += OnRunDestroy;
		}

		internal static void Unapply()
		{
			Run.onRunDestroyGlobal -= OnRunDestroy;
			suppressedUntil.Clear();
		}

		private static void OnRunDestroy(Run run)
		{
			suppressedUntil.Clear();
		}

		private static void PollButtonInputPostfix(PlayerCharacterMasterController __instance)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			InputBankTest bodyInputs = __instance.bodyInputs;
			CharacterBody body = __instance.body;
			if (!Object.op_Implicit((Object)(object)bodyInputs) || !Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			NetworkUser networkUser = __instance.networkUser;
			if ((Object)(object)networkUser == (Object)null || networkUser.localUser == null || networkUser.localUser.isUIFocused)
			{
				return;
			}
			if (holdToWalk.Value)
			{
				Player inputPlayer = networkUser.inputPlayer;
				if (inputPlayer != null && inputPlayer.GetButton(18))
				{
					bodyInputs.sprint.down = false;
					return;
				}
			}
			float value = moveThreshold.Value;
			if (((Vector3)(ref bodyInputs.moveVector)).sqrMagnitude < value * value || (suppressedUntil.TryGetValue(body, out var value2) && Time.time < value2))
			{
				return;
			}
			if ((body.bodyFlags & 0x20) == 0)
			{
				Vector3 aimDirection = bodyInputs.aimDirection;
				aimDirection.y = 0f;
				((Vector3)(ref aimDirection)).Normalize();
				Vector3 moveVector = bodyInputs.moveVector;
				moveVector.y = 0f;
				((Vector3)(ref moveVector)).Normalize();
				if (Vector3.Dot(aimDirection, moveVector) < PlayerCharacterMasterController.sprintMinAimMoveDot)
				{
					return;
				}
			}
			bodyInputs.sprint.down = true;
		}

		private static void SkillExecutePostfix(GenericSkill __instance)
		{
			SkillDef skillDef = __instance.skillDef;
			if (Object.op_Implicit((Object)(object)skillDef) && skillDef.cancelSprintingOnActivation)
			{
				CharacterBody characterBody = __instance.characterBody;
				if (Object.op_Implicit((Object)(object)characterBody) && characte