Decompiled source of SpeedrunUtilsV2 v1.1.0

plugins/SpeedrunUtilsV2/SpeedrunUtilsV2.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Reptile;
using Reptile.Phone;
using SpeedrunUtilsV2.Patches;
using SpeedrunUtilsV2.ProgressTracker;
using SpeedrunUtilsV2.UI;
using UnityEngine;
using UnityEngine.Playables;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("SpeedrunUtilsV2")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SpeedrunUtilsV2")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("95a5680f-233b-41e1-9085-fb74f62592fa")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace SpeedrunUtilsV2
{
	internal static class ConnectionManager
	{
		private enum Commands
		{
			GetCurrentGameTime,
			SetGameTime,
			PauseGameTime,
			UnpauseGameTime,
			Reset,
			StartTimer,
			Split
		}

		private const int BUFFER = 1024;

		private const string TimeFormat = "hh\\:mm\\:ss\\.fffffff";

		private static NetworkStream Stream;

		internal static bool StartingNewGame;

		internal static bool IsConnected
		{
			get
			{
				if (Stream != null)
				{
					return Plugin.liveSplitManager.ConnectionStatus == LiveSplitManager.Status.Connected;
				}
				return false;
			}
		}

		internal static void SetStream(NetworkStream stream)
		{
			Stream = stream;
		}

		private static string GetCommand(Commands command, string parameter)
		{
			if (parameter == null)
			{
				return command.ToString().ToLower();
			}
			return command.ToString().ToLower() + " " + parameter;
		}

		private static async Task<(int, byte[])> SendAndReceiveResponse(Commands command, string parameter = null)
		{
			return await SendAndReceiveResponse(GetCommand(command, parameter));
		}

		private static async Task<bool> SendWithNoResponse(Commands command, string parameter = null)
		{
			return await SendWithNoResponse(GetCommand(command, parameter));
		}

		private static async Task<(int, byte[])> SendAndReceiveResponse(string data)
		{
			if (!(await WriteToStream(Encoding.UTF8.GetBytes(data + "\r\n"))))
			{
				return default((int, byte[]));
			}
			return await ReadCurrentStream();
		}

		private static async Task<bool> SendWithNoResponse(string data)
		{
			return await WriteToStream(Encoding.UTF8.GetBytes(data + "\r\n"));
		}

		private static async Task<bool> WriteToStream(byte[] bytes, bool force = false)
		{
			if (IsConnected)
			{
				try
				{
					await Stream.WriteAsync(bytes, 0, bytes.Length);
					await Stream.FlushAsync();
					return true;
				}
				catch
				{
					return false;
				}
			}
			return false;
		}

		private static async Task<(int, byte[])> ReadCurrentStream()
		{
			try
			{
				if (IsConnected && Stream.DataAvailable)
				{
					byte[] responseBuffer = new byte[1024];
					return (await Stream.ReadAsync(responseBuffer, 0, responseBuffer.Length), responseBuffer);
				}
			}
			catch
			{
				return default((int, byte[]));
			}
			return default((int, byte[]));
		}

		internal static async void StartAddingCutsceneTime(TimeSpan time)
		{
			if (IsConnected)
			{
				await AddCutsceneTime(time);
			}
		}

		private static async Task AddCutsceneTime(TimeSpan time)
		{
			Stopwatch responseTimer = Stopwatch.StartNew();
			(int, byte[]) tuple = await SendAndReceiveResponse(Commands.GetCurrentGameTime);
			responseTimer.Stop();
			var (num, array) = tuple;
			if ((num != 0 || array != null) && TimeSpan.TryParse(Encoding.ASCII.GetString(tuple.Item2, 0, tuple.Item1).Trim(), out var result))
			{
				await SendWithNoResponse(Commands.SetGameTime, (result + time - responseTimer.Elapsed).ToString("hh\\:mm\\:ss\\.fffffff"));
			}
		}

		internal static async void StartPausingTimer()
		{
			if (IsConnected)
			{
				await PauseTimer();
			}
		}

		private static async Task PauseTimer()
		{
			await SendWithNoResponse(Commands.PauseGameTime);
		}

		internal static async void StartUnpausingTimer()
		{
			bool newGame = StartingNewGame;
			StartingNewGame = false;
			if (IsConnected)
			{
				await UnpauseTimer();
				if (newGame)
				{
					await StartNewGame();
				}
			}
		}

		private static async Task UnpauseTimer()
		{
			await SendWithNoResponse(Commands.UnpauseGameTime);
		}

		private static async Task StartNewGame()
		{
			if (IsConnected)
			{
				await NewGame();
			}
		}

		private static async Task NewGame()
		{
			await SendWithNoResponse(Commands.Reset);
			await SendWithNoResponse(Commands.StartTimer);
		}

		internal static async void StartSplit(LiveSplitConfig.Splits split)
		{
			if (IsConnected)
			{
				await Split();
			}
		}

		private static async Task Split()
		{
			await SendWithNoResponse(Commands.Split);
		}

		internal static async Task<TimeSpan> StartGettingGameTime()
		{
			if (IsConnected)
			{
				return await GetGameTimeFull();
			}
			return default(TimeSpan);
		}

		private static async Task<TimeSpan> GetGameTimeFull()
		{
			(int, byte[]) tuple = await SendAndReceiveResponse(Commands.GetCurrentGameTime);
			var (num, array) = tuple;
			if (num == 0 && array == null)
			{
				return default(TimeSpan);
			}
			if (TimeSpan.TryParse(Encoding.ASCII.GetString(tuple.Item2, 0, tuple.Item1).Trim(), out var result))
			{
				return result;
			}
			return default(TimeSpan);
		}
	}
	internal class CutsceneTimer
	{
		private class TimerInfo
		{
			internal TimeSpan StartingTime;

			internal TimeSpan EndingTime;

			internal TimeSpan TotalDelay;

			internal string name;

			internal int playable;

			internal TimerInfo(TimeSpan startingTime, string name, int playable)
			{
				StartingTime = startingTime;
				this.name = name;
				this.playable = playable;
			}
		}

		private TimerInfo ActiveTimer;

		internal async void StartTimer(string name, int playable)
		{
			Debug.Log((object)"Starting Cutscene Timer...");
			Debug.Log((object)$"-- {name} | {playable} --");
			Stopwatch responseTimer = Stopwatch.StartNew();
			ActiveTimer = new TimerInfo(await ConnectionManager.StartGettingGameTime(), name, playable);
			responseTimer.Stop();
			ActiveTimer.TotalDelay = responseTimer.Elapsed;
		}

		internal async void StopTimer()
		{
			if (ActiveTimer != null)
			{
				Stopwatch responseTimer = Stopwatch.StartNew();
				TimerInfo activeTimer = ActiveTimer;
				activeTimer.EndingTime = await ConnectionManager.StartGettingGameTime();
				responseTimer.Stop();
				ActiveTimer.TotalDelay += responseTimer.Elapsed;
				Debug.Log((object)$"{ActiveTimer.name} | {ActiveTimer.playable}");
				Debug.Log((object)"----------------------------");
				Debug.Log((object)$"Final Time:     {ActiveTimer.EndingTime - ActiveTimer.StartingTime - ActiveTimer.TotalDelay}");
				Debug.Log((object)$"Total Delay:    {ActiveTimer.TotalDelay} (Removed from Final Time)");
				Debug.Log((object)"----------------------------");
			}
		}
	}
	internal static class GameStatus
	{
		private static ObjectiveID _currentStoryObjective = (ObjectiveID)(-1);

		private static ObjectiveID PreviousStoryObjective = (ObjectiveID)(-1);

		private static Stage _currentStage = (Stage)(-1);

		private static Stage PreviousStage = (Stage)(-1);

		internal static ObjectiveID CurrentStoryObjective
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				return _currentStoryObjective;
			}
			set
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0001: 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_0013: 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_000d: Unknown result type (might be due to invalid IL or missing references)
				if (value != _currentStoryObjective)
				{
					PreviousStoryObjective = _currentStoryObjective;
				}
				_currentStoryObjective = value;
			}
		}

		internal static Stage CurrentStage
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				return _currentStage;
			}
			set
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0001: 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_0013: 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_000d: Unknown result type (might be due to invalid IL or missing references)
				if (value != _currentStage)
				{
					PreviousStage = _currentStage;
				}
				_currentStage = value;
			}
		}

		internal static void SetupNewGame(SaveSlotData saveSlotData)
		{
			LiveSplitConfig.RefreshSplitsFile();
			LiveSplitConfig.SetDefaultSplitStates();
			Tracking.CreateProgressData(saveSlotData.saveSlotId);
			if (ConnectionManager.IsConnected)
			{
				ConnectionManager.StartingNewGame = true;
			}
		}

		internal static void UpdateStage()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Core instance = Core.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				SaveManager saveManager = instance.SaveManager;
				obj = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
			}
			SaveSlotData val = (SaveSlotData)obj;
			Stage currentStage = Utility.GetCurrentStage();
			if (val != null && (int)currentStage != -1)
			{
				CurrentStoryObjective = val.CurrentStoryObjective;
				CurrentStage = currentStage;
				CheckSplitsForStageChange(CurrentStage, PreviousStage);
			}
		}

		internal static void UpdateObjective(ObjectiveID objectiveID)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if ((int)objectiveID != -1)
			{
				CurrentStoryObjective = objectiveID;
				CheckSplitsForObjectiveChange(CurrentStoryObjective, PreviousStoryObjective);
			}
		}

		internal static void FinalBossDead()
		{
			ShouldSplit(LiveSplitConfig.Splits.FinalBossDefeated);
		}

		private static void CheckSplitsForStageChange(Stage currentStage, Stage previousStage)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Invalid comparison between Unknown and I4
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Invalid comparison between Unknown and I4
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Invalid comparison between Unknown and I4
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Invalid comparison between Unknown and I4
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Invalid comparison between Unknown and I4
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Invalid comparison between Unknown and I4
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Invalid comparison between Unknown and I4
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Invalid comparison between Unknown and I4
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Invalid comparison between Unknown and I4
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Invalid comparison between Unknown and I4
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Invalid comparison between Unknown and I4
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Invalid comparison between Unknown and I4
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Invalid comparison between Unknown and I4
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Invalid comparison between Unknown and I4
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Invalid comparison between Unknown and I4
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Invalid comparison between Unknown and I4
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Invalid comparison between Unknown and I4
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Invalid comparison between Unknown and I4
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Invalid comparison between Unknown and I4
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Invalid comparison between Unknown and I4
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Invalid comparison between Unknown and I4
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Invalid comparison between Unknown and I4
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Invalid comparison between Unknown and I4
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Invalid comparison between Unknown and I4
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Invalid comparison between Unknown and I4
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Invalid comparison between Unknown and I4
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Invalid comparison between Unknown and I4
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Invalid comparison between Unknown and I4
			Core instance = Core.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				SaveManager saveManager = instance.SaveManager;
				obj = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
			}
			SaveSlotData val = (SaveSlotData)obj;
			if (val != null)
			{
				ObjectiveID currentStoryObjective = val.CurrentStoryObjective;
				bool flag = (int)currentStoryObjective == 0 || (int)currentStoryObjective == 1;
				bool flag2 = (int)currentStoryObjective == 15 || (int)currentStoryObjective == 16 || (int)currentStoryObjective == 17 || (int)currentStoryObjective == 18 || (int)currentStoryObjective == 9;
				if ((int)previousStage == 8 && (int)currentStage == 5 && flag)
				{
					ShouldSplit(LiveSplitConfig.Splits.PrologueEnd);
				}
				else if ((int)previousStage == 7 && (int)currentStage == 11 && flag)
				{
					ShouldSplit(LiveSplitConfig.Splits.EarlySquare);
				}
				else if ((((int)previousStage == 11 && (int)currentStage == 4) || ((int)previousStage == 5 && (int)currentStage == 4)) && (flag || (int)currentStoryObjective == 2))
				{
					ShouldSplit(LiveSplitConfig.Splits.VersumStart);
				}
				else if ((int)previousStage == 4 && (int)currentStage == 5 && (int)currentStoryObjective == 4)
				{
					ShouldSplit(LiveSplitConfig.Splits.Chapter1End);
				}
				else if ((int)previousStage == 11 && (int)currentStage == 12 && (int)currentStoryObjective == 5)
				{
					ShouldSplit(LiveSplitConfig.Splits.BrinkStart);
				}
				else if ((int)previousStage == 12 && (int)currentStage == 5 && (int)currentStoryObjective == 7)
				{
					ShouldSplit(LiveSplitConfig.Splits.Chapter2End);
				}
				else if ((int)previousStage == 11 && (int)currentStage == 6 && (int)currentStoryObjective == 7)
				{
					ShouldSplit(LiveSplitConfig.Splits.MallStart);
				}
				else if ((int)previousStage == 6 && (int)currentStage == 5 && (int)currentStoryObjective == 15)
				{
					ShouldSplit(LiveSplitConfig.Splits.Chapter3End);
				}
				else if ((int)previousStage == 11 && (int)currentStage == 9 && flag2)
				{
					ShouldSplit(LiveSplitConfig.Splits.PyramidStart);
				}
				else if ((int)previousStage == 9 && (int)currentStage == 5 && (int)currentStoryObjective == 11)
				{
					ShouldSplit(LiveSplitConfig.Splits.Chapter4End);
				}
			}
		}

		private static void CheckSplitsForObjectiveChange(ObjectiveID currentObjective, ObjectiveID previousObjective)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: 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_0040: Expected I4, but got Unknown
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Invalid comparison between Unknown and I4
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Invalid comparison between Unknown and I4
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Invalid comparison between Unknown and I4
			if ((int)currentObjective != 3)
			{
				switch (currentObjective - 6)
				{
				case 0:
					ShouldSplit(LiveSplitConfig.Splits.Dream2Start);
					break;
				case 2:
					ShouldSplit(LiveSplitConfig.Splits.Dream3Start);
					break;
				case 4:
					ShouldSplit(LiveSplitConfig.Splits.Dream4Start);
					break;
				case 6:
					ShouldSplit(LiveSplitConfig.Splits.Dream5Start);
					break;
				case 10:
					if ((int)previousObjective == 15)
					{
						ShouldSplit(LiveSplitConfig.Splits.PrinceVersumEnd);
					}
					break;
				case 11:
					if ((int)previousObjective == 16)
					{
						ShouldSplit(LiveSplitConfig.Splits.PrinceSquareEnd);
					}
					break;
				case 12:
					if ((int)previousObjective == 17)
					{
						ShouldSplit(LiveSplitConfig.Splits.PrinceBrinkEnd);
					}
					break;
				case 1:
				case 3:
				case 5:
				case 7:
				case 8:
				case 9:
					break;
				}
			}
			else
			{
				ShouldSplit(LiveSplitConfig.Splits.Dream1Start);
			}
		}

		internal static void ShouldSplit(LiveSplitConfig.Splits split, bool ignoreHasBeenSplit = false)
		{
			if (LiveSplitConfig.SETTINGS_DebugMode.Item2)
			{
				Debug.LogWarning((object)$"Trying to split: {split}");
			}
			if (ConnectionManager.IsConnected)
			{
				LiveSplitConfig.RefreshSplitsFile();
				if (LiveSplitConfig.CurrentSplits.TryGetValue(split, out var value) && value.Item1 && (ignoreHasBeenSplit || (LiveSplitConfig.CurrentSplitStates.TryGetValue(split, out var value2) && !value2)))
				{
					LiveSplitConfig.CurrentSplitStates[split] = true;
					ConnectionManager.StartSplit(split);
				}
			}
		}
	}
	internal static class LiveSplitConfig
	{
		internal enum Splits
		{
			PrologueEnd,
			EarlySquare,
			VersumStart,
			Dream1Start,
			Chapter1End,
			BrinkStart,
			Dream2Start,
			Chapter2End,
			MallStart,
			Dream3Start,
			Chapter3End,
			PrinceVersumEnd,
			PrinceSquareEnd,
			PrinceBrinkEnd,
			PyramidStart,
			Dream4Start,
			Chapter4End,
			Dream5Start,
			UnlockOldHead,
			CharacterUnlock,
			FinalBossDefeated
		}

		internal enum Actions
		{
			OpenGUI,
			LimitFPS,
			UncapFPS,
			OpenTracker
		}

		internal static readonly Dictionary<Splits, (bool, bool, string)> CurrentSplits = new Dictionary<Splits, (bool, bool, string)>
		{
			{
				Splits.PrologueEnd,
				(false, true, Localization.Splits.s_PrologueEnd ?? "")
			},
			{
				Splits.EarlySquare,
				(false, true, Localization.Splits.s_EarlySquare ?? "")
			},
			{
				Splits.VersumStart,
				(false, true, Localization.Splits.s_VersumStart ?? "")
			},
			{
				Splits.Dream1Start,
				(false, true, Localization.Splits.s_Dream1Start ?? "")
			},
			{
				Splits.Chapter1End,
				(false, true, Localization.Splits.s_Chapter1End ?? "")
			},
			{
				Splits.BrinkStart,
				(false, true, Localization.Splits.s_BrinkStart ?? "")
			},
			{
				Splits.Dream2Start,
				(false, true, Localization.Splits.s_Dream2Start ?? "")
			},
			{
				Splits.Chapter2End,
				(false, true, Localization.Splits.s_Chapter2End ?? "")
			},
			{
				Splits.MallStart,
				(false, true, Localization.Splits.s_MallStart ?? "")
			},
			{
				Splits.Dream3Start,
				(false, true, Localization.Splits.s_Dream3Start ?? "")
			},
			{
				Splits.Chapter3End,
				(false, true, Localization.Splits.s_Chapter3End ?? "")
			},
			{
				Splits.PrinceVersumEnd,
				(false, false, Localization.Splits.s_PrinceVersumEnd ?? "")
			},
			{
				Splits.PrinceSquareEnd,
				(false, false, Localization.Splits.s_PrinceSquareEnd ?? "")
			},
			{
				Splits.PrinceBrinkEnd,
				(false, false, Localization.Splits.s_PrinceBrinkEnd ?? "")
			},
			{
				Splits.PyramidStart,
				(false, true, Localization.Splits.s_PyramidStart ?? "")
			},
			{
				Splits.Dream4Start,
				(false, true, Localization.Splits.s_Dream4Start ?? "")
			},
			{
				Splits.Chapter4End,
				(false, true, Localization.Splits.s_Chapter4End ?? "")
			},
			{
				Splits.Dream5Start,
				(false, false, Localization.Splits.s_Dream5Start ?? "")
			},
			{
				Splits.UnlockOldHead,
				(false, false, Localization.Splits.s_UnlockOldHead ?? "")
			},
			{
				Splits.CharacterUnlock,
				(false, false, Localization.Splits.s_CharacterUnlock ?? "")
			},
			{
				Splits.FinalBossDefeated,
				(false, true, Localization.Splits.s_FinalBossDefeated ?? "")
			}
		};

		internal static readonly Dictionary<Splits, bool> CurrentSplitStates = new Dictionary<Splits, bool>();

		internal static readonly Dictionary<Actions, KeyCode> ActionKeys = new Dictionary<Actions, KeyCode>
		{
			{
				Actions.OpenGUI,
				(KeyCode)283
			},
			{
				Actions.LimitFPS,
				(KeyCode)108
			},
			{
				Actions.UncapFPS,
				(KeyCode)111
			},
			{
				Actions.OpenTracker,
				(KeyCode)284
			}
		};

		internal static readonly Dictionary<Actions, KeyCode> ActionKeysDefault = new Dictionary<Actions, KeyCode>
		{
			{
				Actions.OpenGUI,
				(KeyCode)283
			},
			{
				Actions.LimitFPS,
				(KeyCode)108
			},
			{
				Actions.UncapFPS,
				(KeyCode)111
			},
			{
				Actions.OpenTracker,
				(KeyCode)284
			}
		};

		internal static (string, int, int) SETTINGS_DefaultFPS = ("Default FPS", 200, 200);

		internal static (string, int, int) SETTINGS_LimitValue = ("Limit FPS Value", 30, 30);

		internal static (string, bool, bool) SETTINGS_Uncap = ("Start Uncapped", false, false);

		internal static (string, bool, bool) SETTINGS_Tracker = ("Start Tracker Open", false, false);

		internal static (string, bool, bool) SETTINGS_Tracking = ("Tracking Game Progress", false, false);

		internal static (string, bool, bool) SETTINGS_Skip = ("Skip Unskippable Cutscenes", true, true);

		internal static (string, bool, bool) SETTINGS_MashEnabled = ("AutoMash Unskippable Cutscenes", true, true);

		internal static (string, bool, bool) SETTINGS_ShowFPS = ("Show FPS", true, true);

		internal static (string, int, int) SETTINGS_FPSSize = ("FPS Size", 33, 33);

		internal static (string, Vector2, Vector2) SETTINGS_FPSPos = ("FPS Screen Position", new Vector2(8f, 4f), new Vector2(8f, 4f));

		internal static (string, bool, bool) SETTINGS_UncapLoading = ("Uncap FPS During Loading", true, true);

		internal static (string, bool, bool) SETTINGS_MouseFix = ("Enable Fix to Menu Mouse", true, true);

		internal static (string, bool, bool) SETTINGS_DebugMode = ("Debug Mode", false, false);

		private const string EXTENSION = ".cfg";

		internal const string EXTENSION_SaveData = ".sru";

		private const string FOLDER_UtilsFolder = "SpeedrunUtilsV2";

		private const string FOLDER_SaveData = "SaveData";

		private static readonly string FILE_Splits = "Splits.cfg";

		private static readonly string FILE_Keys = "Keys.cfg";

		private static readonly string FILE_Settings = "Settings.cfg";

		private static readonly string PATH_Config = Paths.ConfigPath;

		private static readonly string PATH_UtilsConfig = Path.Combine(PATH_Config, "SpeedrunUtilsV2");

		private static readonly string PATH_Splits = Path.Combine(PATH_UtilsConfig, FILE_Splits);

		private static readonly string PATH_Keys = Path.Combine(PATH_UtilsConfig, FILE_Keys);

		private static readonly string PATH_Settings = Path.Combine(PATH_UtilsConfig, FILE_Settings);

		internal static readonly string PATH_SaveData = Path.Combine(PATH_UtilsConfig, "SaveData");

		private const string SECTION_Splits = "Splits";

		private const string SECTION_Keys = "Keys";

		private const string SECTION_Settings = "Settings";

		private static readonly ConfigFile CONFIG_Splits = new ConfigFile(PATH_Splits, true);

		private static readonly ConfigFile CONFIG_Keys = new ConfigFile(PATH_Keys, true);

		private static readonly ConfigFile CONFIG_Settings = new ConfigFile(PATH_Settings, true);

		internal static void ManageConfigFiles()
		{
			CreateSplitsFile();
			CreateKeysFile();
			CreateSettingsFile();
			SetDefaultSplitStates();
		}

		internal static void SetDefaultSplitStates()
		{
			CurrentSplitStates.Clear();
			foreach (object value in Enum.GetValues(typeof(Splits)))
			{
				CurrentSplitStates.Add((Splits)value, value: false);
			}
		}

		internal static void RefreshSplitsFile()
		{
			CreateSplitsFile();
		}

		internal static void UpdateSplitsFile(Splits split, bool value)
		{
			if (CurrentSplits.ContainsKey(split))
			{
				CurrentSplits[split] = (value, CurrentSplits[split].Item2, CurrentSplits[split].Item3);
				ConfigEntry<bool> val = default(ConfigEntry<bool>);
				if (CONFIG_Splits.TryGetEntry<bool>("Splits", CurrentSplits[split].Item3, ref val))
				{
					val.Value = value;
				}
			}
		}

		internal static void UpdateProgressTrackerState(bool value)
		{
			ConfigEntry<bool> val = default(ConfigEntry<bool>);
			if (CONFIG_Settings.TryGetEntry<bool>("Settings", SETTINGS_Tracker.Item1, ref val))
			{
				val.Value = value;
			}
		}

		internal static void UpdateProgressTrackingState(bool value)
		{
			ConfigEntry<bool> val = default(ConfigEntry<bool>);
			if (CONFIG_Settings.TryGetEntry<bool>("Settings", SETTINGS_Tracking.Item1, ref val))
			{
				val.Value = value;
			}
		}

		private static void CreateSplitsFile()
		{
			ConfigEntry<bool> val = default(ConfigEntry<bool>);
			for (int i = 0; i < CurrentSplits.Count; i++)
			{
				Splits key = CurrentSplits.ElementAt(i).Key;
				if (CurrentSplits.TryGetValue(key, out var value))
				{
					CONFIG_Splits.Bind<bool>("Splits", value.Item3, value.Item2, (ConfigDescription)null);
					if (CONFIG_Splits.TryGetEntry<bool>("Splits", value.Item3, ref val))
					{
						CurrentSplits[key] = (val.Value, value.Item2, value.Item3);
					}
				}
			}
		}

		private static void CreateKeysFile()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<KeyCode> val = default(ConfigEntry<KeyCode>);
			foreach (Actions value2 in Enum.GetValues(typeof(Actions)))
			{
				if (ActionKeysDefault.TryGetValue(value2, out var value))
				{
					string text = Regex.Replace(value2.ToString(), "([a-z])([A-Z])", "$1 $2");
					CONFIG_Keys.Bind<KeyCode>("Keys", text, value, (ConfigDescription)null);
					if (CONFIG_Keys.TryGetEntry<KeyCode>("Keys", text, ref val))
					{
						ActionKeys[value2] = val.Value;
					}
				}
			}
		}

		private static void CreateSettingsFile()
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			Plugin.SetMaxFPS(BindSetting(ref SETTINGS_DefaultFPS));
			BindSetting(ref SETTINGS_LimitValue);
			BindSetting(ref SETTINGS_Uncap);
			BindSetting(ref SETTINGS_Tracker);
			BindSetting(ref SETTINGS_Tracking);
			BindSetting(ref SETTINGS_Skip);
			BindSetting(ref SETTINGS_MashEnabled);
			BindSetting(ref SETTINGS_ShowFPS);
			BindSetting(ref SETTINGS_FPSSize);
			BindSetting(ref SETTINGS_FPSPos);
			BindSetting(ref SETTINGS_UncapLoading);
			BindSetting(ref SETTINGS_MouseFix, Localization.Descriptions.s_mouseFix ?? "");
			BindSetting(ref SETTINGS_DebugMode);
		}

		private static T BindSetting<T>(ref (string, T, T) setting, string description = null)
		{
			if (description != null)
			{
				CONFIG_Settings.Bind<T>("Settings", setting.Item1, setting.Item3, description);
			}
			else
			{
				CONFIG_Settings.Bind<T>("Settings", setting.Item1, setting.Item3, (ConfigDescription)null);
			}
			ConfigEntry<T> val = default(ConfigEntry<T>);
			if (CONFIG_Settings.TryGetEntry<T>("Settings", setting.Item1, ref val))
			{
				return setting.Item2 = val.Value;
			}
			return default(T);
		}

		internal static void UpdateFPSSetting(int fps)
		{
			SETTINGS_DefaultFPS.Item2 = fps;
			ConfigEntry<int> val = default(ConfigEntry<int>);
			if (CONFIG_Settings.TryGetEntry<int>("Settings", SETTINGS_DefaultFPS.Item1, ref val))
			{
				val.Value = fps;
			}
		}
	}
	internal class LiveSplitManager
	{
		internal enum Status
		{
			Disconnected,
			Disconnecting,
			Connected,
			Connecting
		}

		private const string IP = "127.0.0.1";

		private const int PORT = 16834;

		private const float RefreshRate = 2f;

		private NetworkStream Stream;

		private CancellationTokenSource cancelRefresh;

		private Status _connectionStatus;

		internal Status ConnectionStatus
		{
			get
			{
				return _connectionStatus;
			}
			private set
			{
				//IL_0116: Unknown result type (might be due to invalid IL or missing references)
				//IL_0120: Expected O, but got Unknown
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Expected O, but got Unknown
				if (value != _connectionStatus)
				{
					switch (value)
					{
					case Status.Connected:
						Patch_CutsceneSkip.OnSkippedCutscene = (Patch_CutsceneSkip.SkippedCutscene)Delegate.Combine(Patch_CutsceneSkip.OnSkippedCutscene, new Patch_CutsceneSkip.SkippedCutscene(ConnectionManager.StartAddingCutsceneTime));
						Patch_Loading.OnEnteredLoading = (Patch_Loading.Loading)Delegate.Combine(Patch_Loading.OnEnteredLoading, new Patch_Loading.Loading(ConnectionManager.StartPausingTimer));
						Patch_Loading.OnExitedLoading = (Patch_Loading.Loading)Delegate.Combine(Patch_Loading.OnExitedLoading, new Patch_Loading.Loading(ConnectionManager.StartUnpausingTimer));
						StageManager.OnStageInitialized += new OnStageInitializedDelegate(GameStatus.UpdateStage);
						Patch_Objective.OnObjectiveChanged = (Patch_Objective.ObjectiveChanged)Delegate.Combine(Patch_Objective.OnObjectiveChanged, new Patch_Objective.ObjectiveChanged(GameStatus.UpdateObjective));
						break;
					case Status.Disconnected:
						Patch_CutsceneSkip.OnSkippedCutscene = (Patch_CutsceneSkip.SkippedCutscene)Delegate.Remove(Patch_CutsceneSkip.OnSkippedCutscene, new Patch_CutsceneSkip.SkippedCutscene(ConnectionManager.StartAddingCutsceneTime));
						Patch_Loading.OnEnteredLoading = (Patch_Loading.Loading)Delegate.Remove(Patch_Loading.OnEnteredLoading, new Patch_Loading.Loading(ConnectionManager.StartPausingTimer));
						Patch_Loading.OnExitedLoading = (Patch_Loading.Loading)Delegate.Remove(Patch_Loading.OnExitedLoading, new Patch_Loading.Loading(ConnectionManager.StartUnpausingTimer));
						StageManager.OnStageInitialized -= new OnStageInitializedDelegate(GameStatus.UpdateStage);
						Patch_Objective.OnObjectiveChanged = (Patch_Objective.ObjectiveChanged)Delegate.Remove(Patch_Objective.OnObjectiveChanged, new Patch_Objective.ObjectiveChanged(GameStatus.UpdateObjective));
						break;
					}
				}
				if (value == Status.Disconnected)
				{
					ConnectionManager.SetStream(null);
				}
				_connectionStatus = value;
			}
		}

		internal LiveSplitManager()
		{
			LiveSplitConfig.ManageConfigFiles();
			ConnectToLiveSplit();
		}

		internal async void ConnectToLiveSplit()
		{
			if (ConnectionStatus != 0)
			{
				return;
			}
			ConnectionStatus = Status.Connecting;
			using (TcpClient client = new TcpClient())
			{
				if (TryConnectToLiveSplit(client))
				{
					using (Stream = client.GetStream())
					{
						ConnectionManager.SetStream(Stream);
						cancelRefresh = new CancellationTokenSource();
						ConnectionStatus = Status.Connected;
						Debug.Log((object)"Connection to LiveSplit was open!");
						while (ConnectionStatus == Status.Connected)
						{
							try
							{
								await Task.Delay(TimeSpan.FromSeconds(2.0), cancelRefresh.Token);
							}
							catch
							{
								break;
							}
							bool flag = ConnectionStatus != Status.Connected;
							if (!flag)
							{
								flag = !(await TryPingClientAsync(client));
							}
							if (flag)
							{
								break;
							}
						}
					}
				}
			}
			ConnectionStatus = Status.Disconnected;
			Debug.LogWarning((object)"Connection to LiveSplit was closed.");
		}

		internal void DisconnectFromLiveSplit()
		{
			if (ConnectionStatus == Status.Connected)
			{
				ConnectionStatus = Status.Disconnecting;
				cancelRefresh?.Cancel();
			}
		}

		private bool TryConnectToLiveSplit(TcpClient client)
		{
			try
			{
				client?.Connect("127.0.0.1", 16834);
				return TryPingClient(client);
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"Failed to connect to LiveSplit: {arg}");
				return false;
			}
		}

		private async Task<bool> TryPingClientAsync(TcpClient client)
		{
			return await TryPingClient(client, isAsync: true);
		}

		private bool TryPingClient(TcpClient client)
		{
			return TryPingClient(client, isAsync: false).GetAwaiter().GetResult();
		}

		private async Task<bool> TryPingClient(TcpClient client, bool isAsync)
		{
			if (client == null || client.Client == null)
			{
				return false;
			}
			try
			{
				if (client.Client.Poll(0, SelectMode.SelectRead) && client.Client.Available == 0)
				{
					byte[] array = new byte[1];
					if (isAsync)
					{
						return await SocketTaskExtensions.ReceiveAsync(client.Client, new ArraySegment<byte>(array), SocketFlags.Peek) != 0;
					}
					return client.Client.Receive(array, SocketFlags.Peek) != 0;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class EasyReflection
	{
		private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly Dictionary<int, (MemberInfo, object[])> Members = new Dictionary<int, (MemberInfo, object[])>();

		private const string EXCEPTION_BadMember = "Type \"{0}\" does not contain matching member \"{1}\" of the given parameters.";

		private const string EXCEPTION_BadType = "The return type \"{0}\" is not assignable from \"{1}\" in \"{2}\".";

		private const string EXCEPTION_BadMemberType = "The member \"{0}\" in \"{1}\" is not a Field type or assignable Property.";

		private const string EXCEPTION_BadInvokeType = "The member \"{0}\" in \"{1}\" is not a Method type.";

		internal static T GetValue<T>(this object obj, string member, params object[] memberParams)
		{
			MemberInfo member2 = obj.GetMember(member, ref memberParams);
			switch (member2.MemberType)
			{
			case MemberTypes.Method:
				if (typeof(T).IsAssignableFrom((member2 as MethodInfo).ReturnType))
				{
					return (T)(member2 as MethodInfo).Invoke(obj, memberParams);
				}
				break;
			case MemberTypes.Field:
				if (typeof(T).IsAssignableFrom((member2 as FieldInfo).FieldType))
				{
					return (T)(member2 as FieldInfo).GetValue(obj);
				}
				break;
			case MemberTypes.Property:
				if (typeof(T).IsAssignableFrom((member2 as PropertyInfo).PropertyType))
				{
					return (T)(member2 as PropertyInfo).GetValue(obj, null);
				}
				break;
			case MemberTypes.NestedType:
				if (typeof(T).IsAssignableFrom(typeof(TypeInfo)))
				{
					return (T)(object)(member2 as TypeInfo);
				}
				break;
			}
			throw new Exception($"The return type \"{typeof(T)}\" is not assignable from \"{member}\" in \"{obj.GetType()}\".");
		}

		internal static TypeInfo GetNestedType(this object obj, string member)
		{
			return obj.GetValue<TypeInfo>(member, Array.Empty<object>());
		}

		internal static void SetValue(this object obj, string member, object value)
		{
			object[] memberParams = Array.Empty<object>();
			MemberInfo member2 = obj.GetMember(member, ref memberParams);
			if (member2.MemberType == MemberTypes.Field)
			{
				(member2 as FieldInfo).SetValue(obj, value);
				return;
			}
			if (member2.MemberType == MemberTypes.Property && (member2 as PropertyInfo).SetMethod != null)
			{
				(member2 as PropertyInfo).SetValue(obj, value);
				return;
			}
			throw new Exception($"The member \"{member}\" in \"{obj.GetType()}\" is not a Field type or assignable Property.");
		}

		internal static void InvokeMethod(this object obj, string member, params object[] memberParams)
		{
			MemberInfo member2 = obj.GetMember(member, ref memberParams);
			if (member2.MemberType == MemberTypes.Method)
			{
				(member2 as MethodInfo).Invoke(obj, memberParams);
				return;
			}
			throw new Exception($"The member \"{member}\" in \"{obj.GetType()}\" is not a Method type.");
		}

		internal static MemberInfo GetMember(this object obj, string member, params object[] memberParams)
		{
			return obj.GetMember(member, ref memberParams);
		}

		private static MemberInfo GetMember(this object obj, string member, ref object[] memberParams)
		{
			int hashCode = (obj.GetType(), member, HashedObjects(memberParams)).GetHashCode();
			if (Members.TryGetValue(hashCode, out var value))
			{
				memberParams = value.Item2;
				return value.Item1;
			}
			MemberInfo memberFinal = obj.GetMemberFinal(member, ref memberParams);
			if (memberFinal == null)
			{
				throw new Exception($"Type \"{obj.GetType()}\" does not contain matching member \"{member}\" of the given parameters.");
			}
			Members.Add(hashCode, (memberFinal, memberParams));
			return memberFinal;
		}

		private static int HashedObjects(object[] memberParams)
		{
			int num = 17;
			for (int i = 0; i < memberParams.Length; i++)
			{
				num = num * 31 + (memberParams[i]?.GetHashCode() ?? 0);
			}
			return num;
		}

		private static MemberInfo GetMemberFinal(this object obj, string member, ref object[] memberParams)
		{
			MemberInfo[] member2 = obj.GetType().GetMember(member, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (member2.Length == 0)
			{
				return null;
			}
			if (member2.Length == 1)
			{
				return member2.First();
			}
			int paramLength = memberParams.Length;
			MethodInfo[] array = member2.Where((MemberInfo x) => x.MemberType == MemberTypes.Method && (x as MethodInfo).GetParameters().Length >= paramLength).Cast<MethodInfo>().ToArray();
			if (array.Length == 1)
			{
				return array.First();
			}
			List<object> list = new List<object>();
			list.AddRange(memberParams);
			MethodInfo[] array2 = array;
			foreach (MethodInfo methodInfo in array2)
			{
				ParameterInfo[] parameters = methodInfo.GetParameters();
				bool flag = true;
				for (int j = 0; j < parameters.Length; j++)
				{
					bool flag2 = memberParams.Length - 1 >= j;
					if (!flag2 && parameters[j].HasDefaultValue)
					{
						list.Add(parameters[j].DefaultValue);
					}
					else if (!flag2 || !(memberParams[j].GetType() == parameters[j].ParameterType))
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					memberParams = list.ToArray();
					return methodInfo;
				}
			}
			return null;
		}
	}
	[BepInPlugin("SpeedrunUtilsV2", "SpeedrunUtilsV2", "1.1.0")]
	internal class Plugin : BaseUnityPlugin
	{
		internal enum FPSStatus
		{
			Uncapped,
			Capped,
			Limited
		}

		private class ScreenInfo
		{
			private const float ReferenceResolution = 1080f;

			internal Vector2Int Resolution { get; private set; }

			internal Matrix4x4 Matrix { get; private set; }

			internal ScreenInfo(int width, int height)
			{
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: 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_0072: Unknown result type (might be due to invalid IL or missing references)
				float num = 1080f * ((float)width / (float)height);
				float num2 = Mathf.Min((float)width / num, (float)height / 1080f);
				float num3 = ((float)width - num * num2) * 0.5f;
				float num4 = ((float)height - 1080f * num2) * 0.5f;
				Resolution = new Vector2Int((int)num, 1080);
				Matrix = Matrix4x4.TRS(new Vector3(num3, num4, 0f), Quaternion.identity, new Vector3(num2, num2, 1f));
			}
		}

		private const string pluginGuid = "SpeedrunUtilsV2";

		private const string pluginName = "SpeedrunUtilsV2";

		private const string pluginVersion = "1.1.0";

		internal static readonly LiveSplitManager liveSplitManager = new LiveSplitManager();

		private bool _GUI_ENABLED;

		private static bool GUI_TRACKER_ENABLED = false;

		private static bool GUI_SPLITS_ENABLED = false;

		private static bool GUI_CREDITS_ENABLED = false;

		private const float FPSUpdateRate = 0.1f;

		private float FPSUpdate = 0.1f;

		private static int FPS = 0;

		private static bool FPS_Limited = false;

		private static UtilsUI.WindowProperties windowPropertiesMain;

		private static UtilsUI.WindowProperties windowPropertiesSplits;

		private static UtilsUI.WindowProperties windowPropertiesCredits;

		internal static UtilsUI.WindowProperties windowPropertiesTracker;

		private static Rect fpsRect;

		private static Rect fpsRectShadow;

		private ScreenInfo CurrentScreenInfo;

		private static string _fps = string.Empty;

		private bool GUI_ENABLED
		{
			get
			{
				return _GUI_ENABLED;
			}
			set
			{
				_GUI_ENABLED = value;
				if (!GUI_ENABLED)
				{
					GUI_SPLITS_ENABLED = false;
					GUI_CREDITS_ENABLED = false;
				}
			}
		}

		private static int FPS_LimitValue => Mathf.Clamp(LiveSplitConfig.SETTINGS_LimitValue.Item2, 30, 9999);

		internal static FPSStatus CurrentFPSStatus
		{
			get
			{
				if (LiveSplitConfig.SETTINGS_UncapLoading.Item2)
				{
					Core instance = Core.Instance;
					if ((Object)(object)((instance != null) ? instance.BaseModule : null) != (Object)null && Core.Instance.BaseModule.IsLoading)
					{
						return FPSStatus.Uncapped;
					}
				}
				if (FPS_Limited)
				{
					return FPSStatus.Limited;
				}
				if (LiveSplitConfig.SETTINGS_Uncap.Item2)
				{
					return FPSStatus.Uncapped;
				}
				return FPSStatus.Capped;
			}
		}

		private static int _fpsInt
		{
			get
			{
				if (int.TryParse(_fps, out var result))
				{
					return result;
				}
				return Application.targetFrameRate;
			}
		}

		internal static string FPSfield
		{
			get
			{
				return _fps;
			}
			set
			{
				if (!(_fps == value))
				{
					string text = Regex.Replace(value, "\\D", "");
					if (text.Length > 4)
					{
						text = _fps;
					}
					_fps = text;
				}
			}
		}

		public void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			SetupProperties(Screen.width, Screen.height);
			Core.OnScreenSizeChanged += new ScreenSizeChangedDelegate(SetupProperties);
			new Harmony("SpeedrunUtilsV2").PatchAll();
		}

		internal static void GUIFront(int windowID)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			string arg = ((CurrentFPSStatus == FPSStatus.Uncapped) ? ("<color=#C0392B>" + Localization.UI.s_uncapped + "</color>") : string.Format("<color={0}>{1}</color>", "#BDC3C7", Application.targetFrameRate));
			UtilsUI.GUILabel($"({arg}) FPS: {FPS}", windowPropertiesMain);
			if (LiveSplitConfig.ActionKeys.TryGetValue(LiveSplitConfig.Actions.UncapFPS, out var value) && LiveSplitConfig.ActionKeys.TryGetValue(LiveSplitConfig.Actions.LimitFPS, out var value2))
			{
				UtilsUI.GUILabel(string.Format("{0}: <color={1}>{2}</color> | {3} {4}: <color={5}>{6}</color>", Localization.UI.s_uncappedFramerate, "#BDC3C7", value, Localization.UI.s_limitFramerateTo, LiveSplitConfig.SETTINGS_LimitValue.Item2, "#BDC3C7", value2), windowPropertiesMain, small: true);
			}
			UtilsUI.GUILabel(ConnectionManager.IsConnected ? ("<color=#2ECC71>" + Localization.UI.s_connected + "</color>") : ("<color=#E74C3C>" + Localization.UI.s_disconnected + "</color>"), windowPropertiesMain);
			if (UtilsUI.GUIButton(ConnectionManager.IsConnected ? (Localization.UI.s_disconnect ?? "") : (Localization.UI.s_connect ?? ""), (!ConnectionManager.IsConnected) ? UtilsUI.Setup.ButtonType.Off : UtilsUI.Setup.ButtonType.On, windowPropertiesMain))
			{
				ToggleLiveSplit();
			}
			if (UtilsUI.GUIButton(Localization.UI.s_splits ?? "", (!GUI_SPLITS_ENABLED) ? UtilsUI.Setup.ButtonType.Off : UtilsUI.Setup.ButtonType.On, windowPropertiesMain))
			{
				GUI_SPLITS_ENABLED = !GUI_SPLITS_ENABLED;
			}
			if (UtilsUI.GUIButton(Localization.UI.s_tracker ?? "", (!GUI_TRACKER_ENABLED) ? UtilsUI.Setup.ButtonType.Off : UtilsUI.Setup.ButtonType.On, windowPropertiesMain))
			{
				ToggleProgressTracker();
			}
			if (UtilsUI.GUIButton(Localization.UI.s_tracking ?? "", (!LiveSplitConfig.SETTINGS_Tracking.Item2) ? UtilsUI.Setup.ButtonType.Off : UtilsUI.Setup.ButtonType.On, windowPropertiesMain))
			{
				ToggleProgressTracking();
			}
			if (UtilsUI.GUIButton(Localization.UI.s_credits ?? "", (!GUI_CREDITS_ENABLED) ? UtilsUI.Setup.ButtonType.Off : UtilsUI.Setup.ButtonType.On, windowPropertiesMain))
			{
				GUI_CREDITS_ENABLED = !GUI_CREDITS_ENABLED;
			}
			UtilsUI.GUIEmptySpace(8f, windowPropertiesMain);
			if (UtilsUI.GUIButton(Localization.UI.s_setMax ?? "", UtilsUI.Setup.ButtonType.Normal, windowPropertiesMain))
			{
				SetMaxFPS(_fpsInt);
			}
			FPSfield = UtilsUI.GUIField(FPSfield, windowPropertiesMain);
			UtilsUI.Cleanup(windowPropertiesMain);
		}

		internal static void GUISplits(int windowID)
		{
			foreach (LiveSplitConfig.Splits value in Enum.GetValues(typeof(LiveSplitConfig.Splits)))
			{
				UpdateSplitGUI(value);
			}
			UtilsUI.Cleanup(windowPropertiesSplits);
		}

		internal static void GUICredits(int windowID)
		{
			UtilsUI.GUILabel("- " + Localization.UI.s_development + " -", windowPropertiesCredits);
			UtilsUI.GUILabel("<color=#FA7DE5>Ninja Cookie</color>", windowPropertiesCredits);
			UtilsUI.GUILabel("<color=#800080>Loomeh</color>", windowPropertiesCredits);
			UtilsUI.GUIEmptySpace(5f, windowPropertiesCredits);
			UtilsUI.GUILabel("- " + Localization.UI.s_research + " -", windowPropertiesCredits);
			UtilsUI.GUILabel("<color=#9FA1A4>Jomoko</color>", windowPropertiesCredits);
			UtilsUI.GUIEmptySpace(5f, windowPropertiesCredits);
			UtilsUI.GUILabel("- " + Localization.UI.s_originalTools + " -", windowPropertiesCredits);
			UtilsUI.GUILabel("<color=#45BF60>Judah Caruso</color>", windowPropertiesCredits);
			UtilsUI.Cleanup(windowPropertiesCredits);
		}

		internal static void GUITracker(int windowID)
		{
			SaveData.Data data = Tracking.CurrentSaveData?.StageData;
			if (LiveSplitConfig.SETTINGS_Tracking.Item2 && data != null && data.StageValid)
			{
				UtilsUI.GUILabelTracker(windowPropertiesTracker, Localization.Tracking.s_total + ":    \t" + data.CurrentTotal, Localization.Tracking.s_graffiti + ": \t" + data.CurrentStageGraffiti, Localization.Tracking.s_taxi + ":     \t" + data.CurrentStageTaxi);
				(string, bool)[] currentStageCollectableInfo = data.CurrentStageCollectableInfo;
				for (int i = 0; i < currentStageCollectableInfo.Length; i++)
				{
					(string, bool) tuple = currentStageCollectableInfo[i];
					UtilsUI.GUILabelLeft("<color=" + GetColorCollected(tuple.Item2) + ">" + tuple.Item1 + "</color>", windowPropertiesTracker);
				}
				currentStageCollectableInfo = data.CurrentStageCharacterInfo;
				for (int i = 0; i < currentStageCollectableInfo.Length; i++)
				{
					(string, bool) tuple2 = currentStageCollectableInfo[i];
					UtilsUI.GUILabelLeft("<color=" + GetColorCollected(tuple2.Item2) + ">" + tuple2.Item1 + "</color>", windowPropertiesTracker);
				}
			}
			else if (LiveSplitConfig.SETTINGS_Tracking.Item2 && data != null)
			{
				UtilsUI.GUILabelLeft("Waiting for stage...", windowPropertiesTracker);
			}
			else if (!LiveSplitConfig.SETTINGS_Tracking.Item2)
			{
				UtilsUI.GUILabelLeft("Tracking Disabled...", windowPropertiesTracker);
			}
			UtilsUI.Cleanup(windowPropertiesTracker);
		}

		private static string GetColorCollected(bool collected = false)
		{
			if (!collected)
			{
				return "#E74C3C";
			}
			return "#2ECC71";
		}

		public void Start()
		{
			GUI_TRACKER_ENABLED = LiveSplitConfig.SETTINGS_Tracker.Item2;
		}

		public void Update()
		{
			if (GetActionKeyDown(LiveSplitConfig.Actions.UncapFPS))
			{
				LiveSplitConfig.SETTINGS_Uncap.Item2 = !LiveSplitConfig.SETTINGS_Uncap.Item2;
			}
			if (GetActionKeyDown(LiveSplitConfig.Actions.LimitFPS))
			{
				FPS_Limited = !FPS_Limited;
			}
			UpdateFPS();
			if (GetActionKeyDown(LiveSplitConfig.Actions.OpenGUI) && windowPropertiesMain != null)
			{
				GUI_ENABLED = !GUI_ENABLED;
			}
			if (GetActionKeyDown(LiveSplitConfig.Actions.OpenTracker) && windowPropertiesMain != null)
			{
				ToggleProgressTracker();
			}
		}

		private bool GetActionKeyDown(LiveSplitConfig.Actions action)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (LiveSplitConfig.ActionKeys.TryGetValue(action, out var value))
			{
				return Input.GetKeyDown(value);
			}
			return false;
		}

		private void UpdateFPS()
		{
			switch (CurrentFPSStatus)
			{
			case FPSStatus.Uncapped:
				if (Application.targetFrameRate != -1)
				{
					SetFPS(-1);
				}
				break;
			case FPSStatus.Capped:
				if (Application.targetFrameRate != LiveSplitConfig.SETTINGS_DefaultFPS.Item2)
				{
					SetMaxFPS(LiveSplitConfig.SETTINGS_DefaultFPS.Item2);
				}
				break;
			case FPSStatus.Limited:
				if (Application.targetFrameRate != FPS_LimitValue)
				{
					SetFPS(LiveSplitConfig.SETTINGS_LimitValue.Item2 = FPS_LimitValue);
				}
				break;
			}
			if (FPSUpdate <= 0f)
			{
				FPS = Mathf.RoundToInt(1f / Time.smoothDeltaTime);
				FPSUpdate = 0.1f;
			}
			FPSUpdate -= Time.deltaTime;
		}

		public void OnGUI()
		{
			//IL_000d: 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_0031: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			ScreenInfo currentScreenInfo = CurrentScreenInfo;
			if (currentScreenInfo != null)
			{
				_ = currentScreenInfo.Matrix;
				if (true)
				{
					GUI.matrix = CurrentScreenInfo.Matrix;
				}
			}
			UtilsUI.Init();
			_ = fpsRect;
			_ = fpsRectShadow;
			if (LiveSplitConfig.SETTINGS_ShowFPS.Item2)
			{
				UtilsUI.GUILabelFPS(FPS.ToString(), fpsRect, fpsRectShadow);
			}
			if (GUI_ENABLED)
			{
				UtilsUI.GUIWindow(0, windowPropertiesMain, new WindowFunction(GUIFront));
				if (GUI_SPLITS_ENABLED)
				{
					UtilsUI.GUIWindow(1, windowPropertiesSplits, new WindowFunction(GUISplits));
				}
				if (GUI_CREDITS_ENABLED)
				{
					UtilsUI.GUIWindow(2, windowPropertiesCredits, new WindowFunction(GUICredits));
				}
			}
			if (GUI_TRACKER_ENABLED)
			{
				UtilsUI.GUIWindow(3, windowPropertiesTracker, new WindowFunction(GUITracker));
			}
		}

		private void SetupProperties(int width, int height)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			CurrentScreenInfo = new ScreenInfo(width, height);
			Vector2Int resolution = CurrentScreenInfo.Resolution;
			width = ((Vector2Int)(ref resolution)).x;
			resolution = CurrentScreenInfo.Resolution;
			height = ((Vector2Int)(ref resolution)).y;
			windowPropertiesMain = new UtilsUI.WindowProperties((float)width * 0.5f - 175f);
			windowPropertiesSplits = new UtilsUI.WindowProperties(windowPropertiesMain.WindowX + 350f + 3f, 300f, 18f);
			windowPropertiesCredits = new UtilsUI.WindowProperties(windowPropertiesMain.WindowX - 200f - 3f, 200f, 18f);
			windowPropertiesTracker = new UtilsUI.WindowProperties((float)width - 300f - 18f, 300f, 18f);
			fpsRect = new Rect(LiveSplitConfig.SETTINGS_FPSPos.Item2.x, LiveSplitConfig.SETTINGS_FPSPos.Item2.y, (float)width, (float)height);
			fpsRectShadow = new Rect(LiveSplitConfig.SETTINGS_FPSPos.Item2.x - 2f, LiveSplitConfig.SETTINGS_FPSPos.Item2.y + 2f, (float)width, (float)height);
		}

		internal static void SetMaxFPS(int fps)
		{
			fps = Mathf.Clamp(fps, 30, 9999);
			if (CurrentFPSStatus != FPSStatus.Capped)
			{
				FPSfield = fps.ToString();
				LiveSplitConfig.UpdateFPSSetting(fps);
			}
			else
			{
				SetFPS(fps);
				LiveSplitConfig.UpdateFPSSetting(Application.targetFrameRate);
				FPSfield = Application.targetFrameRate.ToString();
			}
		}

		private static void SetFPS(int fps)
		{
			if (QualitySettings.vSyncCount > 0)
			{
				QualitySettings.vSyncCount = 0;
			}
			Application.targetFrameRate = fps;
		}

		internal static void ToggleLiveSplit()
		{
			if (!ConnectionManager.IsConnected && liveSplitManager.ConnectionStatus == LiveSplitManager.Status.Disconnected)
			{
				liveSplitManager.ConnectToLiveSplit();
			}
			else if (ConnectionManager.IsConnected && liveSplitManager.ConnectionStatus == LiveSplitManager.Status.Connected)
			{
				liveSplitManager.DisconnectFromLiveSplit();
			}
		}

		internal static void UpdateSplitGUI(LiveSplitConfig.Splits split)
		{
			bool flag = UtilsUI.GUIToggle(LiveSplitConfig.CurrentSplits[split].Item1, LiveSplitConfig.CurrentSplits[split].Item3, windowPropertiesSplits);
			if (LiveSplitConfig.CurrentSplits.TryGetValue(split, out var value) && flag != value.Item1)
			{
				LiveSplitConfig.UpdateSplitsFile(split, flag);
			}
		}

		internal static void ToggleProgressTracker()
		{
			GUI_TRACKER_ENABLED = !GUI_TRACKER_ENABLED;
			LiveSplitConfig.UpdateProgressTrackerState(LiveSplitConfig.SETTINGS_Tracker.Item2 = GUI_TRACKER_ENABLED);
		}

		internal static void ToggleProgressTracking()
		{
			LiveSplitConfig.UpdateProgressTrackingState(LiveSplitConfig.SETTINGS_Tracking.Item2 = !LiveSplitConfig.SETTINGS_Tracking.Item2);
			if (LiveSplitConfig.SETTINGS_Tracking.Item2)
			{
				Tracking.CurrentSaveData?.UpdateAll();
			}
		}
	}
	internal static class Localization
	{
		internal static class UI
		{
			internal static string s_uncapped = "Uncapped";

			internal static string s_uncappedFramerate = "Uncap Framerate";

			internal static string s_limitFramerateTo = "Limit Framerate to";

			internal static string s_connected = "Connected to LiveSplit!";

			internal static string s_disconnected = "Disconnected from LiveSplit";

			internal static string s_connect = "Connect to LiveSplit";

			internal static string s_disconnect = "Disconnect from LiveSplit";

			internal static string s_splits = "Splits";

			internal static string s_setMax = "Set Max FPS";

			internal static string s_credits = "Credits";

			internal static string s_development = "Development";

			internal static string s_research = "Previous Research";

			internal static string s_originalTools = "Original Tools";

			internal static string s_tracker = "Progress Tracker";

			internal static string s_tracking = "Tracking Game Progress";
		}

		internal static class Splits
		{
			internal static string s_PrologueEnd = "Prologue Ended";

			internal static string s_EarlySquare = "Entered Square Early";

			internal static string s_VersumStart = "Entered Versum";

			internal static string s_Dream1Start = "Dream 1 Started";

			internal static string s_Chapter1End = "Chapter 1 Ended";

			internal static string s_BrinkStart = "Entered Brink";

			internal static string s_Dream2Start = "Dream 2 Started";

			internal static string s_Chapter2End = "Chapter 2 Ended";

			internal static string s_MallStart = "Entered Mall";

			internal static string s_Dream3Start = "Dream 3 Started";

			internal static string s_Chapter3End = "Chapter 3 Ended";

			internal static string s_PrinceVersumEnd = "Talked To Frank in Versum";

			internal static string s_PrinceSquareEnd = "Beat the Frank Challenge in Square";

			internal static string s_PrinceBrinkEnd = "Talked To Frank in Brink";

			internal static string s_PyramidStart = "Entered Pyramid Island";

			internal static string s_Dream4Start = "Dream 4 Started";

			internal static string s_Chapter4End = "Chapter 4 Ended";

			internal static string s_Dream5Start = "Dream 5 Started";

			internal static string s_UnlockOldHead = "Unlocked Old Head";

			internal static string s_CharacterUnlock = "Any Character Unlocked Manually";

			internal static string s_FinalBossDefeated = "Defeated Final Boss";
		}

		internal static class Tracking
		{
			internal static string s_total = "Game Total";

			internal static string s_graffiti = "Stage Graffiti";

			internal static string s_taxi = "Stage Taxi";
		}

		internal static class Descriptions
		{
			internal static string s_mouseFix = "Makes it so the mouse does not take priority of selected items if currently using a controller";
		}
	}
}
namespace SpeedrunUtilsV2.UI
{
	internal static class UtilsUI
	{
		internal class WindowProperties
		{
			internal float WindowMarginW = 20f;

			internal float WindowMarginH = 20f;

			internal float WindowMarginIW = 5f;

			internal float WindowMarginIH = 3f;

			internal float WindowX;

			internal float WindowY;

			internal float WindowW = 350f;

			internal float ElementH = 20f;

			internal float Seperation = 3f;

			internal float IndexLine;

			internal float FinalIndex;

			internal Rect ElementRect;

			internal float WindowH => FinalIndex + WindowMarginIH * 2f;

			private float Spacing
			{
				get
				{
					if (IndexLine == 0f)
					{
						return WindowMarginIH;
					}
					return Seperation;
				}
			}

			internal float ElementY => IndexLine + Spacing;

			internal float ElementW => WindowW - WindowMarginIW * 2f;

			internal Rect ElementRectFinal
			{
				get
				{
					//IL_0042: Unknown result type (might be due to invalid IL or missing references)
					((Rect)(ref ElementRect)).y = ElementY;
					((Rect)(ref ElementRect)).width = ElementW;
					IndexLine += ((Rect)(ref ElementRect)).height + Spacing;
					return ElementRect;
				}
			}

			internal WindowProperties(float WindowX = 0f, float WindowW = 350f, float ElementH = 20f, float WindowY = -1f, Rect? customRect = null)
			{
				//IL_00ab: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
				this.WindowX = WindowX;
				this.WindowW = WindowW;
				this.WindowY = ((WindowY != -1f) ? WindowY : WindowMarginH);
				ElementRect = (Rect)(((??)customRect) ?? new Rect(WindowMarginIW, 0f, ElementW, this.ElementH = ElementH));
			}
		}

		internal static class Setup
		{
			internal enum ButtonType
			{
				Normal,
				Off,
				On
			}

			private static readonly Color TextColor = UtilsUIColor.color_text;

			private static readonly Color TextColorShadow = new Color(0f, 0f, 0f, 0.5f);

			private static readonly Color TextColorFps = new Color(1f, 1f, 1f, 0.8f);

			private static int FontSize = 16;

			private static readonly Texture2D Normal_BT = new Texture2D(1, 1);

			private static readonly Texture2D Hover_BT = new Texture2D(1, 1);

			private static readonly Texture2D Active_BT = new Texture2D(1, 1);

			private static readonly Texture2D Normal_BToff = new Texture2D(1, 1);

			private static readonly Texture2D Hover_BToff = new Texture2D(1, 1);

			private static readonly Texture2D Active_BToff = new Texture2D(1, 1);

			private static readonly Texture2D Normal_BTon = new Texture2D(1, 1);

			private static readonly Texture2D Hover_BTon = new Texture2D(1, 1);

			private static readonly Texture2D Active_BTon = new Texture2D(1, 1);

			private static readonly Texture2D WindowTexture = new Texture2D(1, 1);

			internal static GUIStyle Text()
			{
				//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_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: 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_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Expected O, but got Unknown
				GUIStyle val = new GUIStyle
				{
					alignment = (TextAnchor)4,
					wordWrap = false,
					fontSize = FontSize,
					fontStyle = (FontStyle)1
				};
				val.normal.textColor = TextColor;
				val.hover.textColor = TextColor;
				val.active.textColor = TextColor;
				return val;
			}

			internal static GUIStyle TextLeft()
			{
				//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_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: 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_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Expected O, but got Unknown
				GUIStyle val = new GUIStyle
				{
					alignment = (TextAnchor)3,
					wordWrap = false,
					fontSize = (int)((float)FontSize * 0.9f),
					fontStyle = (FontStyle)1
				};
				val.normal.textColor = TextColor;
				val.hover.textColor = TextColor;
				val.active.textColor = TextColor;
				return val;
			}

			internal static GUIStyle TextSmall()
			{
				//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_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Expected O, but got Unknown
				GUIStyle val = new GUIStyle
				{
					alignment = (TextAnchor)4,
					wordWrap = false,
					fontSize = Mathf.RoundToInt((float)FontSize * 0.7f),
					fontStyle = (FontStyle)1
				};
				val.normal.textColor = TextColor;
				val.hover.textColor = TextColor;
				val.active.textColor = TextColor;
				return val;
			}

			internal static GUIStyle TextFPS()
			{
				//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_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Expected O, but got Unknown
				GUIStyle val = new GUIStyle
				{
					alignment = (TextAnchor)0,
					wordWrap = false,
					fontSize = Mathf.Max(LiveSplitConfig.SETTINGS_FPSSize.Item2, 1),
					fontStyle = (FontStyle)1
				};
				val.normal.textColor = TextColorFps;
				val.hover.textColor = TextColorFps;
				val.active.textColor = TextColorFps;
				return val;
			}

			internal static GUIStyle TextFPSShadow()
			{
				//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_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Expected O, but got Unknown
				GUIStyle val = new GUIStyle
				{
					alignment = (TextAnchor)0,
					wordWrap = false,
					fontSize = Mathf.Max(LiveSplitConfig.SETTINGS_FPSSize.Item2, 1),
					fontStyle = (FontStyle)1
				};
				val.normal.textColor = TextColorShadow;
				val.hover.textColor = TextColorShadow;
				val.active.textColor = TextColorShadow;
				return val;
			}

			internal static GUIStyle TextField()
			{
				//IL_000a: 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)
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Expected O, but got Unknown
				return new GUIStyle(GUI.skin.textField)
				{
					alignment = (TextAnchor)4,
					wordWrap = false,
					fontSize = Mathf.RoundToInt((float)FontSize * 0.8f),
					fontStyle = (FontStyle)1
				};
			}

			internal static GUIStyle Window()
			{
				//IL_000a: 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_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Expected O, but got Unknown
				GUIStyle val = new GUIStyle(GUI.skin.box);
				WindowTexture.SetPixel(0, 0, new Color(0.073f, 0.123f, 0.155f, 0.75f));
				WindowTexture.Apply();
				val.normal.background = WindowTexture;
				return val;
			}

			internal static GUIStyle Button(ButtonType buttonType)
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Expected O, but got Unknown
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_0084: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
				//IL_0116: Unknown result type (might be due to invalid IL or missing references)
				//IL_0132: Unknown result type (might be due to invalid IL or missing references)
				GUIStyle val = new GUIStyle(GUI.skin.button);
				Texture2D val2 = Normal_BT;
				Texture2D val3 = Hover_BT;
				Texture2D val4 = Active_BT;
				switch (buttonType)
				{
				case ButtonType.Normal:
					val2.SetPixel(0, 0, UtilsUIColor.color_button);
					val3.SetPixel(0, 0, UtilsUIColor.color_button_hover);
					val4.SetPixel(0, 0, UtilsUIColor.color_button_active);
					break;
				case ButtonType.Off:
					val2 = Normal_BToff;
					val3 = Hover_BToff;
					val4 = Active_BToff;
					val2.SetPixel(0, 0, UtilsUIColor.color_button_off);
					val3.SetPixel(0, 0, UtilsUIColor.color_button_off_hover);
					val4.SetPixel(0, 0, UtilsUIColor.color_button_off_active);
					break;
				case ButtonType.On:
					val2 = Normal_BTon;
					val3 = Hover_BTon;
					val4 = Active_BTon;
					val2.SetPixel(0, 0, UtilsUIColor.color_button_on);
					val3.SetPixel(0, 0, UtilsUIColor.color_button_on_hover);
					val4.SetPixel(0, 0, UtilsUIColor.color_button_on_active);
					break;
				}
				val2.Apply();
				val3.Apply();
				val4.Apply();
				val.normal.background = val2;
				val.normal.textColor = TextColor;
				val.hover.background = val3;
				val.hover.textColor = TextColor;
				val.active.background = val4;
				val.active.textColor = TextColor;
				val.alignment = (TextAnchor)4;
				val.wordWrap = false;
				val.fontSize = Mathf.RoundToInt((float)FontSize * 0.8f);
				val.fontStyle = (FontStyle)1;
				return val;
			}

			internal static GUIStyle Toggle()
			{
				//IL_000a: 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)
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Expected O, but got Unknown
				return new GUIStyle(GUI.skin.toggle)
				{
					alignment = (TextAnchor)4,
					wordWrap = false,
					fontSize = Mathf.RoundToInt((float)FontSize * 0.8f),
					fontStyle = (FontStyle)1
				};
			}
		}

		internal static bool setup;

		private const string WINDOWNAME = "";

		private static GUIStyle TEXT;

		private static GUIStyle TEXT_LEFT;

		private static GUIStyle TEXT_SMALL;

		private static GUIStyle TEXT_FPS;

		private static GUIStyle TEXT_FPS_SHADOW;

		private static GUIStyle WINDOW;

		private static GUIStyle BUTTON;

		private static GUIStyle BUTTON_OFF;

		private static GUIStyle BUTTON_ON;

		private static GUIStyle FIELD;

		private static GUIStyle TOGGLE;

		internal static void Init()
		{
			if (!setup)
			{
				TEXT = Setup.Text();
				TEXT_LEFT = Setup.TextLeft();
				TEXT_SMALL = Setup.TextSmall();
				TEXT_FPS = Setup.TextFPS();
				TEXT_FPS_SHADOW = Setup.TextFPSShadow();
				WINDOW = Setup.Window();
				BUTTON = Setup.Button(Setup.ButtonType.Normal);
				BUTTON_OFF = Setup.Button(Setup.ButtonType.Off);
				BUTTON_ON = Setup.Button(Setup.ButtonType.On);
				FIELD = Setup.TextField();
				TOGGLE = Setup.Toggle();
				setup = true;
			}
		}

		internal static void GUIWindow(int ID, WindowProperties windowProperties, WindowFunction func)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			GUI.Window(ID, new Rect(windowProperties.WindowX, windowProperties.WindowY, windowProperties.WindowW, windowProperties.WindowH), func, "", WINDOW);
		}

		internal static void GUILabel(string text, WindowProperties windowProperties, bool small = false, bool fps = false)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			GUI.Label(windowProperties.ElementRectFinal, text, fps ? TEXT_FPS : (small ? TEXT_SMALL : TEXT));
		}

		internal static void GUILabelLeft(string text, WindowProperties windowProperties)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			GUI.Label(windowProperties.ElementRectFinal, text, TEXT_LEFT);
		}

		internal static void GUILabelTracker(WindowProperties windowProperties, params string[] texts)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			foreach (string text in texts)
			{
				GUI.Label(windowProperties.ElementRectFinal, text, TEXT_LEFT);
			}
		}

		internal static void GUILabelFPS(string text, Rect rect, Rect shadow)
		{
			//IL_0000: 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)
			GUI.Label(shadow, text, TEXT_FPS_SHADOW);
			GUI.Label(rect, text, TEXT_FPS);
		}

		internal static void GUIEmptySpace(float space, WindowProperties windowProperties)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			((Rect)(ref windowProperties.ElementRect)).height = space;
			GUI.Label(windowProperties.ElementRectFinal, "", TEXT);
			((Rect)(ref windowProperties.ElementRect)).height = windowProperties.ElementH;
		}

		internal static bool GUIButton(string text, Setup.ButtonType buttonType, WindowProperties windowProperties)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			GUIStyle val = BUTTON;
			switch (buttonType)
			{
			case Setup.ButtonType.Normal:
				val = BUTTON;
				break;
			case Setup.ButtonType.Off:
				val = BUTTON_OFF;
				break;
			case Setup.ButtonType.On:
				val = BUTTON_ON;
				break;
			}
			return GUI.Button(windowProperties.ElementRectFinal, text, val);
		}

		internal static string GUIField(string text, WindowProperties windowProperties)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return GUI.TextField(windowProperties.ElementRectFinal, text, FIELD);
		}

		internal static bool GUIToggle(bool value, string text, WindowProperties windowProperties)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return GUI.Toggle(windowProperties.ElementRectFinal, value, text, TOGGLE);
		}

		internal static void Cleanup(WindowProperties windowProperties)
		{
			if (windowProperties.FinalIndex == 0f)
			{
				windowProperties.FinalIndex = windowProperties.IndexLine;
			}
			windowProperties.IndexLine = 0f;
		}
	}
	internal static class UtilsUIColor
	{
		internal const string color_text_disconnect = "#E74C3C";

		internal const string color_text_connect = "#2ECC71";

		internal const string color_text_keys = "#BDC3C7";

		internal const string color_text_red = "#C0392B";

		internal const string color_text_fps = "#BDC3C7";

		internal const string color_credit_ninja = "#FA7DE5";

		internal const string color_credit_loomeh = "#800080";

		internal const string color_credit_jomoko = "#9FA1A4";

		internal const string color_credit_judah = "#45BF60";

		internal static readonly Color color_text = new Color(0.9254902f, 0.9411765f, 0.94509804f, 1f);

		internal static readonly Color color_button_off = new Color(0.8980392f, 19f / 85f, 0.20784314f, 0.7f);

		internal static readonly Color color_button_off_hover = new Color(0.827451f, 0.18431373f, 0.18431373f, 0.7f);

		internal static readonly Color color_button_off_active = new Color(61f / 85f, 0.10980392f, 0.10980392f, 0.7f);

		internal static readonly Color color_button_on = new Color(0.2627451f, 32f / 51f, 0.2784314f, 1f);

		internal static readonly Color color_button_on_hover = new Color(0.21960784f, 0.5568628f, 0.23529412f, 1f);

		internal static readonly Color color_button_on_active = new Color(0.18039216f, 25f / 51f, 10f / 51f, 1f);

		internal static readonly Color color_button = new Color(47f / 85f, 54f / 85f, 0.7490196f, 0.7f);

		internal static readonly Color color_button_hover = new Color(0.47843137f, 0.58431375f, 0.6901961f, 0.7f);

		internal static readonly Color color_button_active = new Color(36f / 85f, 0.52156866f, 0.6313726f, 0.7f);
	}
}
namespace SpeedrunUtilsV2.ProgressTracker
{
	internal static class Tracking
	{
		internal enum PickupType
		{
			Collectable,
			Pickup
		}

		internal static SaveData CurrentSaveData = new SaveData();

		internal static void CreateProgressData(int id)
		{
			CurrentSaveData = new SaveData();
			SaveProgressData(id);
		}

		internal static void SaveProgressData(int id)
		{
			//IL_005d: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			if (TryGetDirectory(out var directory))
			{
				using BinaryWriter writer = new BinaryWriter(new FileStream(Path.Combine(directory, string.Format("data_{0}{1}", id, ".sru")), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None));
				Write(writer);
			}
			SaveData.Data data = CurrentSaveData?.StageData;
			if (data != null)
			{
				data.StageValid = SaveData.FromReptileStage(Utility.GetCurrentStage()) != SaveData.Stage.MAX;
				CurrentSaveData.GetPercentageTotal();
				if (data.StageValid)
				{
					CurrentSaveData.GetPercentageStageTotal();
					CurrentSaveData.StageData.CurrentStageGraffiti = CurrentSaveData.GetPercentage(data.Graffiti, Utility.GetCurrentStage());
					CurrentSaveData.StageData.CurrentStageTaxi = CurrentSaveData.GetPercentage(data.Taxis, Utility.GetCurrentStage());
				}
			}
		}

		internal static SaveData LoadProgressData(int id)
		{
			return CurrentSaveData = new SaveData(GetProgressData(id));
		}

		private static SaveData.Data GetProgressData(int id)
		{
			SaveData.Data result = new SaveData.Data();
			string path = Path.Combine(LiveSplitConfig.PATH_SaveData, string.Format("data_{0}{1}", id, ".sru"));
			if (!File.Exists(path))
			{
				return result;
			}
			try
			{
				using BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None));
				return Read(reader);
			}
			catch
			{
				return result = new SaveData.Data();
			}
		}

		private static void Write(BinaryWriter writer)
		{
			float[] graffiti = CurrentSaveData.StageData.Graffiti;
			foreach (float value in graffiti)
			{
				writer.Write(value);
			}
			graffiti = CurrentSaveData.StageData.Collectables;
			foreach (float value2 in graffiti)
			{
				writer.Write(value2);
			}
			graffiti = CurrentSaveData.StageData.Characters;
			foreach (float value3 in graffiti)
			{
				writer.Write(value3);
			}
			graffiti = CurrentSaveData.StageData.Taxis;
			foreach (float value4 in graffiti)
			{
				writer.Write(value4);
			}
		}

		private static SaveData.Data Read(BinaryReader reader)
		{
			SaveData.Data data = new SaveData.Data();
			for (int i = 0; i < data.Graffiti.Length; i++)
			{
				data.Graffiti[i] = reader.ReadSingle();
			}
			for (int j = 0; j < data.Collectables.Length; j++)
			{
				data.Collectables[j] = reader.ReadSingle();
			}
			for (int k = 0; k < data.Characters.Length; k++)
			{
				data.Characters[k] = reader.ReadSingle();
			}
			for (int l = 0; l < data.Taxis.Length; l++)
			{
				data.Taxis[l] = reader.ReadSingle();
			}
			return data;
		}

		private static bool TryGetDirectory(out string directory)
		{
			if (Directory.Exists(directory = LiveSplitConfig.PATH_SaveData))
			{
				return true;
			}
			try
			{
				if (Directory.CreateDirectory(LiveSplitConfig.PATH_SaveData).Exists)
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		internal static (Object, PickupType)[] GetCurrentStagePickups()
		{
			//IL_0012: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Invalid comparison between Unknown and I4
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			List<Pickup> list = new List<Pickup>();
			Collectable[] array = Array.Empty<Collectable>();
			List<(Object, PickupType)> list2 = new List<(Object, PickupType)>();
			Stage currentStage = Utility.GetCurrentStage();
			Core instance = Core.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				SaveManager saveManager = instance.SaveManager;
				obj = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
			}
			if (obj == null || (int)currentStage == -1 || (int)currentStage == 14)
			{
				return list2.ToArray();
			}
			if (Core.Instance.SaveManager.CurrentSaveSlot.GetStageProgress(currentStage) == null)
			{
				return list2.ToArray();
			}
			WorldHandler instance2 = WorldHandler.instance;
			array = ((instance2 == null) ? null : instance2.SceneObjectsRegister?.gameplayEvents?.Where((GameplayEvent x) => ((object)x).GetType() == typeof(Collectable))?.Cast<Collectable>()?.ToArray());
			if (array == null)
			{
				return list2.ToArray();
			}
			VendingMachine[] array2 = Object.FindObjectsOfType<VendingMachine>()?.Where((VendingMachine x) => x.rewards != null && x.rewards.Contains((Reward)4))?.ToArray();
			if (array2 != null)
			{
				VendingMachine[] array3 = array2;
				Pickup item = default(Pickup);
				foreach (VendingMachine val in array3)
				{
					if ((Object)(object)val.unlockableDrop != (Object)null && val.unlockableDrop.TryGetComponent<Pickup>(ref item))
					{
						list.Add(item);
					}
				}
			}
			Pickup val2 = WorldHandler.instance.SceneObjectsRegister.pickups?.FirstOrDefault((Func<Pickup, bool>)((Pickup x) => (int)x.pickupType == 10));
			if ((Object)(object)val2 != (Object)null)
			{
				list.Add(val2);
			}
			foreach (Pickup item3 in list)
			{
				list2.Add(((Object)(object)item3, PickupType.Pickup));
			}
			Collectable[] array4 = array;
			foreach (Collectable item2 in array4)
			{
				list2.Add(((Object)(object)item2, PickupType.Collectable));
			}
			return list2.ToArray();
		}
	}
	internal class SaveData
	{
		[Serializable]
		internal class Data
		{
			internal float[] Graffiti = new float[7];

			internal float[] Collectables = new float[7];

			internal float[] Characters = new float[7];

			internal float[] Taxis = new float[7];

			internal string CurrentTotal = string.Empty;

			internal string CurrentStageTotal = string.Empty;

			internal string CurrentStageGraffiti = string.Empty;

			internal string CurrentStageTaxi = string.Empty;

			internal bool StageValid;

			internal (string, bool)[] CurrentStageCollectableInfo = Array.Empty<(string, bool)>();

			internal (string, bool)[] CurrentStageCharacterInfo = Array.Empty<(string, bool)>();
		}

		internal enum Stage
		{
			NONE = -1,
			Hideout,
			Versum,
			Square,
			Brink,
			Mall,
			Pyramid,
			Mataan,
			MAX
		}

		internal static readonly Dictionary<Characters, Stage> CharacterList = new Dictionary<Characters, Stage>
		{
			{
				(Characters)8,
				(Stage)5
			},
			{
				(Characters)0,
				(Stage)5
			},
			{
				(Characters)6,
				(Stage)4
			},
			{
				(Characters)1,
				(Stage)4
			},
			{
				(Characters)14,
				(Stage)4
			},
			{
				(Characters)9,
				(Stage)11
			},
			{
				(Characters)19,
				(Stage)12
			},
			{
				(Characters)10,
				(Stage)12
			},
			{
				(Characters)7,
				(Stage)6
			},
			{
				(Characters)22,
				(Stage)6
			},
			{
				(Characters)21,
				(Stage)9
			},
			{
				(Characters)11,
				(Stage)9
			},
			{
				(Characters)2,
				(Stage)7
			},
			{
				(Characters)20,
				(Stage)7
			},
			{
				(Characters)13,
				(Stage)7
			}
		};

		internal Data StageData { get; private set; }

		internal SaveData(Data data = null)
		{
			StageData = data ?? new Data();
		}

		internal string GetPercentageTotal()
		{
			if (StageData == null)
			{
				return 0f.ToString("##0.00") + "%";
			}
			float[] data = new float[4]
			{
				GetProgress(StageData.Graffiti),
				GetProgress(StageData.Collectables),
				GetProgress(StageData.Characters),
				GetProgress(StageData.Taxis)
			};
			return StageData.CurrentTotal = GetPercentage(data);
		}

		internal string GetPercentageStageTotal()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			int num = (int)FromReptileStage(Utility.GetCurrentStage());
			if (StageData == null || StageData.Graffiti?.Length < num + 1 || StageData.Collectables?.Length < num + 1 || StageData.Characters?.Length < num + 1 || StageData.Taxis?.Length < num + 1)
			{
				return 0f.ToString("##0.00") + "%";
			}
			float[] data = new float[4]
			{
				StageData.Graffiti[num],
				StageData.Collectables[num],
				StageData.Characters[num],
				StageData.Taxis[num]
			};
			return StageData.CurrentStageTotal = GetPercentage(data);
		}

		internal string GetPercentage(float[] data, Stage? stage = null)
		{
			return GetProgress(data, stage).ToString("##0.00") + "%";
		}

		internal float GetProgress(float[] data, Stage? stage = null)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (stage.HasValue)
			{
				int num = (int)FromReptileStage(stage.Value);
				if (num == -1 || data == null || data.Length < num + 1)
				{
					return 0f;
				}
				return data[num];
			}
			if (data == null)
			{
				return 0f;
			}
			float num2 = 0f;
			foreach (float num3 in data)
			{
				num2 += num3;
			}
			return num2 / ((float)data.Length * 100f) * 100f;
		}

		internal void UpdateAll()
		{
			if (LiveSplitConfig.SETTINGS_Tracking.Item2)
			{
				UpdateTaxis(save: false);
				UpdateCurrentStageGraffiti(save: false);
				UpdateCurrentStageCollectables(save: false);
				UpdateCurrentCharacters(save: false);
				Core instance = Core.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					SaveManager saveManager = instance.SaveManager;
					obj = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
				}
				SaveSlotData val = (SaveSlotData)obj;
				if (val != null)
				{
					Tracking.SaveProgressData(val.saveSlotId);
				}
				if (Plugin.windowPropertiesTracker != null)
				{
					Plugin.windowPropertiesTracker.FinalIndex = 0f;
				}
			}
		}

		internal void UpdateTaxis(bool save = true)
		{
			//IL_003e: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Invalid comparison between Unknown and I4
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			Core instance = Core.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				SaveManager saveManager = instance.SaveManager;
				obj = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
			}
			SaveSlotData val = (SaveSlotData)obj;
			if (val == null || StageData?.Taxis == null)
			{
				return;
			}
			for (int i = 0; i < StageData.Taxis.Length; i++)
			{
				Stage val2 = ToReptileStage((Stage)i);
				bool flag = StageData.Taxis.Length >= i + 1;
				if (flag && (int)val2 != 11)
				{
					StageData.Taxis[i] = (val.GetStageProgress(val2).taxiFound ? 100f : 0f);
				}
				else if (flag && (int)val2 == 11)
				{
					float num = (val.GetStageProgress(val2).taxiFound ? 50f : 0f);
					if (!val.taxiLocked)
					{
						num += 50f;
					}
					StageData.Taxis[i] = num;
				}
			}
			if (save)
			{
				Tracking.SaveProgressData(val.saveSlotId);
			}
		}

		internal void UpdateCurrentStageGraffiti(bool save = true)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)WorldHandler.instance == (Object)null)
			{
				return;
			}
			Core instance = Core.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				SaveManager saveManager = instance.SaveManager;
				obj = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
			}
			if (obj == null)
			{
				return;
			}
			GraffitiSpot[] array = (from x in WorldHandler.instance.GetGrafSpots(false)
				where !(x is GraffitiSpotFinisher)
				select x).ToArray();
			float num = (float)array.Where((GraffitiSpot x) => (int)x.topCrew == 1 || (int)x.topCrew == 7).Count() / (float)array.Length * 100f;
			int num2 = (int)FromReptileStage(Utility.GetCurrentStage());
			if (num2 != -1 && StageData.Graffiti != null && StageData.Graffiti.Length >= num2 + 1)
			{
				StageData.Graffiti[num2] = num;
				if (save)
				{
					Tracking.SaveProgressData(Core.Instance.SaveManager.CurrentSaveSlot.saveSlotId);
				}
			}
		}

		private string GetLocalizedCollectableName(AUnlockable unlockable, PickUpType type)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected I4, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			string text = string.Empty;
			Core instance = Core.Instance;
			IGameTextLocalizer val = ((instance != null) ? instance.Localizer : null);
			if (val == null)
			{
				return string.Empty;
			}
			switch (type - 3)
			{
			case 0:
				text = ((MusicTrack)(((unlockable is MusicTrack) ? unlockable : null)?)).Title;
				break;
			case 1:
				text = ((GraffitiAppEntry)(((unlockable is GraffitiAppEntry) ? unlockable : null)?)).Title;
				break;
			case 8:
				text = val.GetSkinText(((MoveStyleSkin)(((unlockable is MoveStyleSkin) ? unlockable : null)?)).Title, Array.Empty<string>());
				break;
			case 2:
				text = val.GetSkinText(((OutfitUnlockable)((unlockable is OutfitUnlockable) ? unlockable : null)).outfitName, Array.Empty<string>()) + " (" + val.GetCharacterName(((OutfitUnlockable)((unlockable is OutfitUnlockable) ? unlockable : null)).character) + ")";
				break;
			case 7:
				text = "Map";
				break;
			}
			return text ?? string.Empty;
		}

		internal void UpdateCurrentStageCollectables(bool save = true)
		{
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Invalid comparison between Unknown and I4
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Invalid comparison between Unknown and I4
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			Core instance = Core.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				APlatform platform = instance.Platform;
				obj = ((platform != null) ? platform.User : null);
			}
			AUser val = (AUser)obj;
			if ((Object)(object)WorldHandler.instance == (Object)null)
			{
				return;
			}
			Core instance2 = Core.Instance;
			object obj2;
			if (instance2 == null)
			{
				obj2 = null;
			}
			else
			{
				SaveManager saveManager = instance2.SaveManager;
				obj2 = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
			}
			if (obj2 == null || val == null)
			{
				return;
			}
			(Object, Tracking.PickupType)[] currentStagePickups = Tracking.GetCurrentStagePickups();
			float num = 0f;
			List<(string, bool)> list = new List<(string, bool)>();
			(Object, Tracking.PickupType)[] array = currentStagePickups;
			for (int i = 0; i < array.Length; i++)
			{
				(Object, Tracking.PickupType) tuple = array[i];
				switch (tuple.Item2)
				{
				case Tracking.PickupType.Pickup:
				{
					Object item3 = tuple.Item1;
					Pickup val4 = (Pickup)(object)((item3 is Pickup) ? item3 : null);
					AUnlockable val5 = val4?.unlock;
					bool item4 = false;
					if (((int)val4.pickupType == 10 && Core.Instance.SaveManager.CurrentSaveSlot.GetCurrentStageProgress().mapFound) || ((int)val4.pickupType != 10 && (Object)(object)val5 != (Object)null && val.GetUnlockableSaveDataFor(val5).IsUnlocked))
					{
						num += 1f;
						item4 = true;
					}
					list.Add((GetLocalizedCollectableName(val5, val4.pickupType), item4));
					break;
				}
				case Tracking.PickupType.Collectable:
				{
					Object item = tuple.Item1;
					Collectable val2 = (Collectable)(object)((item is Collectable) ? item : null);
					AUnlockable val3 = val2?.unlock;
					bool item2 = false;
					if ((Object)(object)val3 != (Object)null && val.GetUnlockableSaveDataFor(val3).IsUnlocked)
					{
						num += 1f;
						item2 = true;
					}
					list.Add((GetLocalizedCollectableName(val3, val2.GetValue<PickUpType>("pickUpType", Array.Empty<object>())), item2));
					break;
				}
				}
			}
			float num2 = num / (float)currentStagePickups.Length * 100f;
			int num3 = (int)FromReptileStage(Utility.GetCurrentStage());
			if (num3 != -1 && StageData?.Collectables != null && StageData.Collectables.Length >= num3 + 1)
			{
				StageData.CurrentStageCollectableInfo = list.ToArray();
				StageData.Collectables[num3] = num2;
				if (save)
				{
					Tracking.SaveProgressData(Core.Instance.SaveManager.CurrentSaveSlot.saveSlotId);
				}
			}
		}

		internal void UpdateCurrentCharacters(bool save = true)
		{
			//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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			Core instance = Core.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				SaveManager saveManager = instance.SaveManager;
				obj = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
			}
			if (obj == null || StageData?.Characters == null)
			{
				return;
			}
			Core instance2 = Core.Instance;
			IGameTextLocalizer val = ((instance2 != null) ? instance2.Localizer : null);
			List<(string, bool)> list = new List<(string, bool)>();
			for (int i = 0; i < StageData.Characters.Length; i++)
			{
				Stage stage = ToReptileStage((Stage)i);
				Characters[] array = CharacterList.Where((KeyValuePair<Characters, Stage> x) => x.Value == stage)?.Select((KeyValuePair<Characters, Stage> x) => x.Key)?.ToArray();
				if (array == null || array.Length == 0)
				{
					continue;
				}
				List<Characters> list2 = new List<Characters>();
				Characters[] array2 = array;
				foreach (Characters val2 in array2)
				{
					CharacterProgress characterProgress = Core.Instance.SaveManager.CurrentSaveSlot.GetCharacterProgress(val2);
					if (characterProgress != null)
					{
						bool item = false;
						if (characterProgress.unlocked)
						{
							list2.Add(val2);
							item = true;
						}
						if (stage == Utility.GetCurrentStage())
						{
							list.Add((((val != null) ? val.GetCharacterName(val2) : null) ?? string.Empty, item));
						}
					}
				}
				float num = (float)list2.Count / (float)array.Length * 100f;
				if (StageData.Characters.Length >= i + 1)
				{
					StageData.Characters[i] = num;
				}
			}
			StageData.CurrentStageCharacterInfo = list.ToArray();
			if (save)
			{
				Tracking.SaveProgressData(Core.Instance.SaveManager.CurrentSaveSlot.saveSlotId);
			}
		}

		internal static Stage FromReptileStage(Stage stage)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected I4, but got Unknown
			return (stage - 4) switch
			{
				1 => Stage.Hideout, 
				0 => Stage.Versum, 
				7 => Stage.Square, 
				8 => Stage.Brink, 
				2 => Stage.Mall, 
				5 => Stage.Pyramid, 
				3 => Stage.Mataan, 
				_ => Stage.MAX, 
			};
		}

		internal static St