Decompiled source of EasyPZ v3.0.0

plugins/EasyPZ/EasyPZ.dll

Decompiled 4 months ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using Configgy;
using Configgy.Assets;
using Configgy.UI;
using EasyPZ.Components;
using EasyPZ.Properties;
using EasyPZ.UIEdit;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using Steamworks.Data;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Hydraxous")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Tiny QoL mod for P-Ranking in ULTRAKILL")]
[assembly: AssemblyFileVersion("2.0.2.0")]
[assembly: AssemblyInformationalVersion("2.0.2+5f9ae9dd0c50f4870db3da8f40cbd0c9d724dce4")]
[assembly: AssemblyProduct("EasyPZ")]
[assembly: AssemblyTitle("EasyPZ")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace EasyPZ
{
	internal static class Paths
	{
		[Configgable("Ghosts/Recording", "Recording Path", 0, null)]
		public static ConfigInputField<string> ghostRecordingPath = new ConfigInputField<string>(DataFolder, (Func<string, bool>)null, (Func<string, ValueTuple<bool, string>>)null);

		public static string ExecutionPath => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		public static string DataFolder => Path.Combine(ExecutionPath, "GhostRecordings");

		[Configgable("Ghosts/Recording", "Open Recordings Folder", 0, null)]
		public static void OpenDataFolder()
		{
			Application.OpenURL(((ConfigValueElement<string>)(object)ghostRecordingPath).Value);
		}
	}
	public static class ConstInfo
	{
		public const string NAME = "EasyPZ";

		public const string GUID = "Hydraxous.ULTRAKILL.EasyPZ";

		public const string VERSION = "3.0.0";

		public const string GITHUB_URL = "https://www.github.com/Hydraxous/EasyPZ-ULTRAKILL";

		public const string GITHUB_VERSION_URL = "https://api.github.com/repos/Hydraxous/EasyPZ-ULTRAKILL/tags";

		public const string KOFI_URL = "https://www.ko-fi.com/Hydraxous";

		public const string DISCORD_URL = "https://discord.gg/kCHnwMDPt4";
	}
	public static class GhostFileManager
	{
		public static List<SessionRecordingMetadata> FetchMetadata()
		{
			string value = ((ConfigValueElement<string>)(object)Paths.ghostRecordingPath).Value;
			if (!Directory.Exists(value))
			{
				return new List<SessionRecordingMetadata>();
			}
			DirectoryInfo directoryInfo = new DirectoryInfo(value);
			List<SessionRecordingMetadata> list = new List<SessionRecordingMetadata>();
			FileInfo[] files = directoryInfo.GetFiles("*.ukrun", SearchOption.AllDirectories);
			foreach (FileInfo fileInfo in files)
			{
				try
				{
					SessionRecordingMetadata sessionRecordingMetadata = SessionRecording.LoadMetadataOnlyFromFilePath(fileInfo.FullName);
					sessionRecordingMetadata.LocatedFilePath = fileInfo.FullName;
					list.Add(sessionRecordingMetadata);
				}
				catch (Exception ex)
				{
					Debug.LogError((object)ex);
				}
			}
			return list;
		}

		internal static void UpdateMetadata(SessionRecordingMetadata metadata)
		{
			if (string.IsNullOrEmpty(metadata.LocatedFilePath))
			{
				throw new Exception("Cannot update metadata without a file path");
			}
			if (!File.Exists(metadata.LocatedFilePath))
			{
				throw new Exception("File does not exist or was moved.");
			}
			SessionRecording sessionRecording = SessionRecording.LoadFromBytes(File.ReadAllBytes(metadata.LocatedFilePath));
			sessionRecording.Metadata = metadata;
			File.WriteAllBytes(metadata.LocatedFilePath, sessionRecording.ToBytes());
		}

		internal static void DeleteRun(SessionRecordingMetadata metadata)
		{
			if (string.IsNullOrEmpty(metadata.LocatedFilePath))
			{
				throw new Exception("Cannot update metadata without a file path");
			}
			if (File.Exists(metadata.LocatedFilePath))
			{
				File.Delete(metadata.LocatedFilePath);
			}
		}

		[Configgable("Extras/Advanced", "Print Metadata", 0, null)]
		public static void PrintFileMetaData()
		{
			string value = ((ConfigValueElement<string>)(object)Paths.ghostRecordingPath).Value;
			DirectoryInfo directoryInfo = new DirectoryInfo(value);
			StringBuilder stringBuilder = new StringBuilder();
			FileInfo[] files = directoryInfo.GetFiles("*.ukrun", SearchOption.AllDirectories);
			foreach (FileInfo fileInfo in files)
			{
				try
				{
					stringBuilder.Clear();
					SessionRecordingMetadata sessionRecordingMetadata = SessionRecording.LoadMetadataOnlyFromFilePath(fileInfo.FullName);
					stringBuilder.AppendLine("FILE: " + fileInfo.FullName);
					stringBuilder.AppendLine("LEVEL: " + sessionRecordingMetadata.LevelName);
					stringBuilder.AppendLine($"STEAMID: {sessionRecordingMetadata.SteamID}");
					stringBuilder.AppendLine($"LENGTH: {sessionRecordingMetadata.TotalLength}");
					stringBuilder.AppendLine("GAMEVERSION: " + sessionRecordingMetadata.GameVersion);
					stringBuilder.AppendLine("MODVERSION: " + sessionRecordingMetadata.ModVersion);
					stringBuilder.AppendLine("TITLE: " + sessionRecordingMetadata.Title);
					stringBuilder.AppendLine("DESC: " + sessionRecordingMetadata.Description);
					stringBuilder.AppendLine($"DIFF: {sessionRecordingMetadata.Difficulty}");
					stringBuilder.AppendLine();
					Debug.Log((object)stringBuilder.ToString());
				}
				catch (Exception ex)
				{
					Debug.LogError((object)ex);
				}
			}
		}
	}
	public static class InGameCheck
	{
		public enum UKLevelType
		{
			Intro,
			MainMenu,
			Level,
			Endless,
			Sandbox,
			Credits,
			Custom,
			Intermission,
			Secret,
			PrimeSanctum,
			Unknown
		}

		public delegate void OnLevelChangedHandler(UKLevelType uKLevelType);

		private static bool initialized;

		public static UKLevelType CurrentLevelType = UKLevelType.Intro;

		public static string CurrentSceneName = "";

		public static OnLevelChangedHandler OnLevelTypeChanged;

		public static OnLevelChangedHandler OnLevelChanged;

		[Configgable("Extras/Advanced", "Force Tracker In All Scenes", 0, null)]
		private static ConfigToggle CFG_ForceInLevelCheckTrue = new ConfigToggle(false);

		public static void Init()
		{
			if (!initialized)
			{
				initialized = true;
				SceneManager.sceneLoaded += OnSceneLoad;
			}
		}

		private static void OnSceneLoad(Scene scene, LoadSceneMode loadSceneMode)
		{
			//IL_0001: 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)
			if (!(scene != SceneManager.GetActiveScene()))
			{
				UKLevelType uKLevelType = GetUKLevelType(SceneHelper.CurrentScene);
				if (uKLevelType != CurrentLevelType)
				{
					CurrentLevelType = uKLevelType;
					CurrentSceneName = SceneHelper.CurrentScene;
					OnLevelTypeChanged?.Invoke(uKLevelType);
				}
				OnLevelChanged?.Invoke(CurrentLevelType);
			}
		}

		public static UKLevelType GetUKLevelType(string sceneName)
		{
			sceneName = (sceneName.Contains("P-") ? "Sanctum" : sceneName);
			sceneName = (sceneName.Contains("-S") ? "Secret" : sceneName);
			sceneName = (sceneName.Contains("Level") ? "Level" : sceneName);
			sceneName = (sceneName.Contains("Intermission") ? "Intermission" : sceneName);
			return sceneName switch
			{
				"Main Menu" => UKLevelType.MainMenu, 
				"Custom Content" => UKLevelType.Custom, 
				"Intro" => UKLevelType.Intro, 
				"Endless" => UKLevelType.Endless, 
				"uk_construct" => UKLevelType.Sandbox, 
				"Intermission" => UKLevelType.Intermission, 
				"Level" => UKLevelType.Level, 
				"Secret" => UKLevelType.Secret, 
				"Sanctum" => UKLevelType.PrimeSanctum, 
				"CreditsMuseum2" => UKLevelType.Credits, 
				_ => UKLevelType.Unknown, 
			};
		}

		public static bool InLevel()
		{
			if (((ConfigValueElement<bool>)(object)CFG_ForceInLevelCheckTrue).Value)
			{
				return true;
			}
			UKLevelType currentLevelType = CurrentLevelType;
			UKLevelType uKLevelType = currentLevelType;
			if ((uint)uKLevelType <= 1u || (uint)(uKLevelType - 7) <= 1u)
			{
				return false;
			}
			return true;
		}
	}
	[BepInPlugin("Hydraxous.ULTRAKILL.EasyPZ", "EasyPZ", "3.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class EasyPZ : BaseUnityPlugin
	{
		private Harmony harmony;

		public static AssetLoader AssetLoader { get; private set; }

		public static EasyPZ Instance { get; private set; }

		public static ConfigBuilder ConfigBuilder { get; private set; }

		public static string LatestVersion { get; private set; } = "3.0.0";


		public static bool UsingLatestVersion { get; private set; } = true;


		private void Awake()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			Instance = this;
			AssetLoader = new AssetLoader(EasyPZResources.EasyPZ);
			harmony = new Harmony("Hydraxous.ULTRAKILL.EasyPZ.harmony");
			harmony.PatchAll();
			ConfigBuilder = new ConfigBuilder("Hydraxous.ULTRAKILL.EasyPZ", "EasyPZ");
			ConfigBuilder.Build();
			InGameCheck.Init();
			GhostManager.PreloadGhostPrefab();
			VersionCheck.CheckVersion("https://api.github.com/repos/Hydraxous/EasyPZ-ULTRAKILL/tags", "3.0.0", (Action<bool, string>)delegate(bool r, string version)
			{
				UsingLatestVersion = r;
				if (!r)
				{
					LatestVersion = version;
					Debug.LogWarning((object)("EasyPZ is out of date. New version available (" + version + ")"));
				}
			});
			((BaseUnityPlugin)this).Logger.LogInfo((object)"EasyPZ Loaded. Good luck on P-ing in all the levels! :D");
		}
	}
	public static class Prefabs
	{
		public static GameObject ClassicTrackerPrefab => EasyPZ.AssetLoader.LoadAsset<GameObject>("ClassicTracker");

		public static GameObject StandardTracker => EasyPZ.AssetLoader.LoadAsset<GameObject>("StandardTracker");

		public static GameObject CompactTracker => EasyPZ.AssetLoader.LoadAsset<GameObject>("CompactTracker");

		public static GameObject TrackerManager => EasyPZ.AssetLoader.LoadAsset<GameObject>("TrackerManager");

		public static GameObject RunManagerMenu => EasyPZ.AssetLoader.LoadAsset<GameObject>("RunManagerMenu");

		public static GameObject PlayerNameplate => EasyPZ.AssetLoader.LoadAsset<GameObject>("PlayerNameplate");

		public static GameObject GhostSavedNotifier => EasyPZ.AssetLoader.LoadAsset<GameObject>("GhostSavedNotifier");

		public static Material GhostMaterial => EasyPZ.AssetLoader.LoadAsset<Material>("GhostMaterial");

		public static AudioClip ShittyBoom => EasyPZ.AssetLoader.LoadAsset<AudioClip>("ShittyBoom");

		public static Font VCR_Font => EasyPZ.AssetLoader.LoadAsset<Font>("VCR_OSD_MONO");
	}
	public static class Restarter
	{
		[Configgable("Auto Restart", "Restart Type", 0, null)]
		private static ConfigDropdown<RestartType> restartType = new ConfigDropdown<RestartType>((RestartType[])Enum.GetValues(typeof(RestartType)), ((RestartType[])Enum.GetValues(typeof(RestartType))).Select((RestartType x) => x.ToString()).ToArray(), 0);

		[Configgable("Auto Restart", "Sound Effect On Auto Restart", 0, null)]
		private static ConfigToggle soundEffectOnAutoRestart = new ConfigToggle(true);

		private static AudioClip _customSound;

		private static readonly string[] fileFormats = new string[3] { ".wav", ".mp3", ".ogg" };

		private static AudioSource _audioSource;

		private static AudioClip _restartClip;

		private static AudioClip customSound
		{
			get
			{
				if ((Object)(object)_customSound == (Object)null)
				{
				}
				return _customSound;
			}
		}

		private static AudioSource audioSource
		{
			get
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_audioSource == (Object)null)
				{
					_audioSource = new GameObject("EZPZ Beeper").AddComponent<AudioSource>();
					_audioSource.playOnAwake = false;
					_audioSource.loop = false;
					_audioSource.volume = 1f;
					_audioSource.spatialBlend = 0f;
					_audioSource.clip = restartClip;
					Object.DontDestroyOnLoad((Object)(object)((Component)_audioSource).gameObject);
				}
				return _audioSource;
			}
		}

		private static AudioClip restartClip
		{
			get
			{
				if ((Object)(object)_restartClip == (Object)null)
				{
					_restartClip = Prefabs.ShittyBoom;
				}
				return _restartClip;
			}
		}

		private static bool ValidateSoundFileLocation(string filePath)
		{
			if (!File.Exists(filePath))
			{
				Debug.LogError((object)("File " + filePath + " not found!"));
				return false;
			}
			for (int i = 0; i < fileFormats.Length; i++)
			{
				if (filePath.EndsWith(fileFormats[i]))
				{
					return true;
				}
			}
			Debug.LogError((object)("File " + filePath + " filetype not supported!"));
			return false;
		}

		public static void Restart()
		{
			if (((ConfigValueElement<bool>)(object)soundEffectOnAutoRestart).Value)
			{
				audioSource.Play();
			}
			MonoSingleton<OptionsManager>.Instance.RestartMission();
		}

		private static IEnumerator RestartAfterTime(float time)
		{
			yield return (object)new WaitForSeconds(time);
			MonoSingleton<OptionsManager>.Instance.RestartMission();
		}
	}
	public enum RestartType
	{
		Standard
	}
	public class RunManagerInterface : IConfigElement
	{
		private ConfigBuilder config;

		private ConfiggableAttribute configgableAttribute;

		public void BindConfig(ConfigBuilder configBuilder)
		{
			config = configBuilder;
		}

		public void BindDescriptor(ConfiggableAttribute configgable)
		{
			configgableAttribute = configgable;
		}

		public void BuildElement(RectTransform rect)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Vector2 sizeDelta = rect.sizeDelta;
			sizeDelta.y *= 20f;
			rect.sizeDelta = sizeDelta;
			RectTransform runEditMenu = null;
			Text runEditLevelName = null;
			Text runEditDate = null;
			Text runEditRunnerName = null;
			Text runTime = null;
			Text runKills = null;
			Text runDeaths = null;
			Text runStyle = null;
			InputField runEditTitle = null;
			InputField runEditDescription = null;
			Button backButton = null;
			Button saveButton = null;
			Button deleteButton = null;
			DynUI.Div(rect, (Action<RectTransform>)delegate(RectTransform editorRoot)
			{
				runEditMenu = editorRoot;
				VerticalLayoutGroup val19 = ((Component)editorRoot).gameObject.AddComponent<VerticalLayoutGroup>();
				ContentSizeFitter val20 = ((Component)editorRoot).gameObject.AddComponent<ContentSizeFitter>();
				val20.verticalFit = (FitMode)2;
				((HorizontalOrVerticalLayoutGroup)val19).childForceExpandWidth = true;
				((HorizontalOrVerticalLayoutGroup)val19).childForceExpandHeight = false;
				((HorizontalOrVerticalLayoutGroup)val19).childControlHeight = false;
				DynUI.Div(editorRoot, (Action<RectTransform>)delegate(RectTransform buttonsDiv)
				{
					//IL_0003: 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)
					buttonsDiv.sizeDelta = new Vector2(buttonsDiv.sizeDelta.x, 40f);
					HorizontalLayoutGroup val27 = ((Component)buttonsDiv).gameObject.AddComponent<HorizontalLayoutGroup>();
					((HorizontalOrVerticalLayoutGroup)val27).childForceExpandWidth = true;
					((HorizontalOrVerticalLayoutGroup)val27).childForceExpandHeight = true;
					((HorizontalOrVerticalLayoutGroup)val27).childControlHeight = true;
					((HorizontalOrVerticalLayoutGroup)val27).childControlWidth = true;
					((LayoutGroup)val27).childAlignment = (TextAnchor)4;
					DynUI.Button(buttonsDiv, (Action<Button>)delegate(Button b)
					{
						((Component)b).GetComponentInChildren<Text>().text = "BACK";
						backButton = b;
					});
					DynUI.Button(buttonsDiv, (Action<Button>)delegate(Button b)
					{
						((Component)b).GetComponentInChildren<Text>().text = "SAVE";
						saveButton = b;
					});
					DynUI.Button(buttonsDiv, (Action<Button>)delegate(Button b)
					{
						((Component)b).GetComponentInChildren<Text>().text = "DELETE";
						deleteButton = b;
					});
				});
				DynUI.Div(editorRoot, (Action<RectTransform>)delegate(RectTransform headerDiv)
				{
					//IL_0003: 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)
					headerDiv.sizeDelta = new Vector2(headerDiv.sizeDelta.x, 40f);
					HorizontalLayoutGroup val26 = ((Component)headerDiv).gameObject.AddComponent<HorizontalLayoutGroup>();
					((HorizontalOrVerticalLayoutGroup)val26).childForceExpandWidth = true;
					((HorizontalOrVerticalLayoutGroup)val26).childForceExpandHeight = true;
					((HorizontalOrVerticalLayoutGroup)val26).childControlHeight = true;
					((HorizontalOrVerticalLayoutGroup)val26).childControlWidth = true;
					((LayoutGroup)val26).childAlignment = (TextAnchor)4;
					DynUI.InputField(headerDiv, (Action<InputField>)delegate(InputField inputField)
					{
						inputField.SetTextWithoutNotify("RUN_TITLE");
						inputField.textComponent.fontSize = 18;
						inputField.textComponent.alignment = (TextAnchor)3;
						runEditTitle = inputField;
					});
					DynUI.Label(headerDiv, (Action<Text>)delegate(Text t)
					{
						t.text = "RUN_DATE";
						t.fontSize = 18;
						t.alignment = (TextAnchor)5;
						runEditDate = t;
					});
				});
				DynUI.Div(editorRoot, (Action<RectTransform>)delegate(RectTransform headerDiv)
				{
					//IL_0003: 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)
					headerDiv.sizeDelta = new Vector2(headerDiv.sizeDelta.x, 20f);
					HorizontalLayoutGroup val25 = ((Component)headerDiv).gameObject.AddComponent<HorizontalLayoutGroup>();
					((HorizontalOrVerticalLayoutGroup)val25).childForceExpandWidth = true;
					((HorizontalOrVerticalLayoutGroup)val25).childForceExpandHeight = true;
					((HorizontalOrVerticalLayoutGroup)val25).childControlHeight = true;
					((HorizontalOrVerticalLayoutGroup)val25).childControlWidth = true;
					((LayoutGroup)val25).childAlignment = (TextAnchor)4;
					DynUI.Label(headerDiv, (Action<Text>)delegate(Text t)
					{
						t.text = "RUNNER_NAME";
						t.fontSize = 18;
						t.alignment = (TextAnchor)3;
						runEditRunnerName = t;
					});
					DynUI.Label(headerDiv, (Action<Text>)delegate(Text t)
					{
						t.text = "LEVEL_NAME";
						t.fontSize = 18;
						t.alignment = (TextAnchor)5;
						runEditLevelName = t;
					});
				});
				DynUI.Div(editorRoot, (Action<RectTransform>)delegate(RectTransform subDiv)
				{
					VerticalLayoutGroup val23 = ((Component)subDiv).gameObject.AddComponent<VerticalLayoutGroup>();
					ContentSizeFitter val24 = ((Component)subDiv).gameObject.AddComponent<ContentSizeFitter>();
					val24.verticalFit = (FitMode)2;
					((HorizontalOrVerticalLayoutGroup)val23).childForceExpandWidth = true;
					((HorizontalOrVerticalLayoutGroup)val23).childForceExpandHeight = false;
					((HorizontalOrVerticalLayoutGroup)val23).childControlHeight = false;
					DynUI.InputField(subDiv, (Action<InputField>)delegate(InputField inputField)
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0019: Unknown result type (might be due to invalid IL or missing references)
						RectTransform component8 = ((Component)inputField).GetComponent<RectTransform>();
						component8.sizeDelta = new Vector2(component8.sizeDelta.x, 100f);
						inputField.textComponent.fontSize = 18;
						inputField.textComponent.alignment = (TextAnchor)0;
						inputField.SetTextWithoutNotify("RUN_DESCRIPTION");
						runEditDescription = inputField;
					});
				});
				DynUI.Div(editorRoot, (Action<RectTransform>)delegate(RectTransform subDiv)
				{
					VerticalLayoutGroup val21 = ((Component)subDiv).gameObject.AddComponent<VerticalLayoutGroup>();
					ContentSizeFitter val22 = ((Component)subDiv).gameObject.AddComponent<ContentSizeFitter>();
					val22.verticalFit = (FitMode)2;
					((HorizontalOrVerticalLayoutGroup)val21).childForceExpandWidth = true;
					((HorizontalOrVerticalLayoutGroup)val21).childForceExpandHeight = false;
					((HorizontalOrVerticalLayoutGroup)val21).childControlHeight = false;
					DynUI.Label(subDiv, (Action<Text>)delegate(Text timeText)
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0019: Unknown result type (might be due to invalid IL or missing references)
						RectTransform component7 = ((Component)timeText).GetComponent<RectTransform>();
						component7.sizeDelta = new Vector2(component7.sizeDelta.x, 25f);
						timeText.fontSize = 18;
						timeText.alignment = (TextAnchor)3;
						timeText.text = "RUN_TIME";
						runTime = timeText;
					});
					DynUI.Label(subDiv, (Action<Text>)delegate(Text killsText)
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0019: Unknown result type (might be due to invalid IL or missing references)
						RectTransform component6 = ((Component)killsText).GetComponent<RectTransform>();
						component6.sizeDelta = new Vector2(component6.sizeDelta.x, 25f);
						killsText.fontSize = 18;
						killsText.alignment = (TextAnchor)3;
						killsText.text = "RUN_KILLS";
						runKills = killsText;
					});
					DynUI.Label(subDiv, (Action<Text>)delegate(Text styleText)
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0019: Unknown result type (might be due to invalid IL or missing references)
						RectTransform component5 = ((Component)styleText).GetComponent<RectTransform>();
						component5.sizeDelta = new Vector2(component5.sizeDelta.x, 25f);
						styleText.fontSize = 18;
						styleText.alignment = (TextAnchor)3;
						styleText.text = "RUN_STYLE";
						runStyle = styleText;
					});
					DynUI.Label(subDiv, (Action<Text>)delegate(Text deathText)
					{
						//IL_000a: Unknown result type (might be due to invalid IL or missing references)
						//IL_0019: Unknown result type (might be due to invalid IL or missing references)
						RectTransform component4 = ((Component)deathText).GetComponent<RectTransform>();
						component4.sizeDelta = new Vector2(component4.sizeDelta.x, 25f);
						deathText.fontSize = 18;
						deathText.alignment = (TextAnchor)3;
						deathText.text = "RUN_STYLE";
						runDeaths = deathText;
					});
				});
			});
			((Component)runEditMenu).gameObject.SetActive(false);
			RectTransform levelFolders = null;
			List<SessionRecordingMetadata> metadatas = GhostFileManager.FetchMetadata();
			List<string> source = (from x in metadatas.Select((SessionRecordingMetadata x) => x.LevelName).Distinct()
				orderby x
				select x).ToList();
			Dictionary<string, List<SessionRecordingMetadata>> levelsDict = source.ToDictionary((string x) => x, (string x) => metadatas.Where((SessionRecordingMetadata y) => y.LevelName == x).ToList());
			DynUI.Div(rect, (Action<RectTransform>)delegate(RectTransform foldersRoot)
			{
				levelFolders = foldersRoot;
				VerticalLayoutGroup val = ((Component)foldersRoot).gameObject.AddComponent<VerticalLayoutGroup>();
				ContentSizeFitter val2 = ((Component)foldersRoot).gameObject.AddComponent<ContentSizeFitter>();
				val2.verticalFit = (FitMode)2;
				((HorizontalOrVerticalLayoutGroup)val).childForceExpandWidth = true;
				((HorizontalOrVerticalLayoutGroup)val).childForceExpandHeight = false;
				((HorizontalOrVerticalLayoutGroup)val).childControlHeight = false;
				DynUI.Label(foldersRoot, (Action<Text>)delegate(Text t)
				{
					t.text = "--- Levels ---";
					t.fontSize = 18;
					t.alignment = (TextAnchor)4;
				});
				foreach (KeyValuePair<string, List<SessionRecordingMetadata>> levelRuns in levelsDict)
				{
					Button levelFolderButton = null;
					RectTransform runList = null;
					UnityAction val3 = default(UnityAction);
					DynUI.Div(rect, (Action<RectTransform>)delegate(RectTransform levelRunListRoot)
					{
						runList = levelRunListRoot;
						VerticalLayoutGroup val14 = ((Component)levelRunListRoot).gameObject.AddComponent<VerticalLayoutGroup>();
						ContentSizeFitter val15 = ((Component)levelRunListRoot).gameObject.AddComponent<ContentSizeFitter>();
						val15.verticalFit = (FitMode)2;
						((HorizontalOrVerticalLayoutGroup)val14).childForceExpandWidth = true;
						((HorizontalOrVerticalLayoutGroup)val14).childForceExpandHeight = false;
						((HorizontalOrVerticalLayoutGroup)val14).childControlHeight = false;
						DynUI.Div(runList, (Action<RectTransform>)delegate(RectTransform buttonsDiv)
						{
							//IL_0003: 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)
							buttonsDiv.sizeDelta = new Vector2(buttonsDiv.sizeDelta.x, 40f);
							HorizontalLayoutGroup val16 = ((Component)buttonsDiv).gameObject.AddComponent<HorizontalLayoutGroup>();
							((HorizontalOrVerticalLayoutGroup)val16).childForceExpandWidth = true;
							((HorizontalOrVerticalLayoutGroup)val16).childForceExpandHeight = true;
							((HorizontalOrVerticalLayoutGroup)val16).childControlHeight = true;
							((HorizontalOrVerticalLayoutGroup)val16).childControlWidth = true;
							((LayoutGroup)val16).childAlignment = (TextAnchor)4;
							DynUI.Button(buttonsDiv, (Action<Button>)delegate(Button b)
							{
								//IL_002a: Unknown result type (might be due to invalid IL or missing references)
								//IL_002f: Unknown result type (might be due to invalid IL or missing references)
								//IL_0031: Expected O, but got Unknown
								//IL_0036: Expected O, but got Unknown
								((Component)b).GetComponentInChildren<Text>().text = "BACK";
								ButtonClickedEvent onClick4 = b.onClick;
								UnityAction obj4 = val3;
								if (obj4 == null)
								{
									UnityAction val17 = delegate
									{
										((Component)runList).gameObject.SetActive(false);
										((Component)levelFolders).gameObject.SetActive(true);
									};
									UnityAction val18 = val17;
									val3 = val17;
									obj4 = val18;
								}
								((UnityEvent)onClick4).AddListener(obj4);
							});
						});
						DynUI.Label(levelRunListRoot, (Action<Text>)delegate(Text t)
						{
							t.text = "--- " + levelRuns.Key + " Runs ---";
							t.fontSize = 18;
							t.alignment = (TextAnchor)4;
						});
						((Component)runList).gameObject.SetActive(false);
					});
					UnityAction val4 = default(UnityAction);
					DynUI.Button(levelFolders, (Action<Button>)delegate(Button b)
					{
						//IL_0011: Unknown result type (might be due to invalid IL or missing references)
						//IL_0020: Unknown result type (might be due to invalid IL or missing references)
						//IL_0085: Unknown result type (might be due to invalid IL or missing references)
						//IL_008a: Unknown result type (might be due to invalid IL or missing references)
						//IL_008c: Expected O, but got Unknown
						//IL_0091: Expected O, but got Unknown
						levelFolderButton = b;
						RectTransform component3 = ((Component)b).GetComponent<RectTransform>();
						component3.sizeDelta = new Vector2(component3.sizeDelta.x, 35f);
						Text componentInChildren2 = ((Component)b).GetComponentInChildren<Text>();
						componentInChildren2.text = $"{levelRuns.Key} ({levelRuns.Value.Count})";
						ButtonClickedEvent onClick3 = b.onClick;
						UnityAction obj3 = val4;
						if (obj3 == null)
						{
							UnityAction val12 = delegate
							{
								((Component)levelFolders).gameObject.SetActive(false);
								((Component)runList).gameObject.SetActive(true);
								Canvas.ForceUpdateCanvases();
							};
							UnityAction val13 = val12;
							val4 = val12;
							obj3 = val13;
						}
						((UnityEvent)onClick3).AddListener(obj3);
					});
					bool spawnToggles = levelRuns.Key == SceneHelper.CurrentScene;
					UnityAction val5 = default(UnityAction);
					foreach (SessionRecordingMetadata metadata in levelRuns.Value.OrderByDescending((SessionRecordingMetadata x) => x.DateCreated.Ticks))
					{
						List<Toggle> soloToggles = new List<Toggle>();
						DynUI.Div(runList, (Action<RectTransform>)delegate(RectTransform listElement)
						{
							//IL_0021: 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)
							listElement.sizeDelta = new Vector2(listElement.sizeDelta.x, 35f);
							HorizontalLayoutGroup val6 = ((Component)listElement).gameObject.AddComponent<HorizontalLayoutGroup>();
							((HorizontalOrVerticalLayoutGroup)val6).childForceExpandWidth = false;
							((HorizontalOrVerticalLayoutGroup)val6).childForceExpandHeight = true;
							((HorizontalOrVerticalLayoutGroup)val6).childControlHeight = true;
							((HorizontalOrVerticalLayoutGroup)val6).childControlWidth = false;
							((LayoutGroup)val6).childAlignment = (TextAnchor)4;
							if (spawnToggles)
							{
								DynUI.Toggle(listElement, (Action<Toggle>)delegate(Toggle toggle)
								{
									//IL_002c: Unknown result type (might be due to invalid IL or missing references)
									RectTransform component2 = ((Component)toggle).GetComponent<RectTransform>();
									component2.sizeDelta = new Vector2(35f, 35f);
									soloToggles.Add(toggle);
									((UnityEvent<bool>)(object)toggle.onValueChanged).AddListener((UnityAction<bool>)delegate(bool state)
									{
										if (state)
										{
											foreach (Toggle item in soloToggles)
											{
												if (!((Object)(object)item == (Object)(object)toggle))
												{
													item.SetIsOnWithoutNotify(false);
												}
											}
											GhostManager ghostManager = Object.FindObjectOfType<GhostManager>();
											if (!((Object)(object)ghostManager != (Object)null))
											{
											}
										}
									});
								});
							}
							DynUI.Button(listElement, (Action<Button>)delegate(Button b)
							{
								//IL_0027: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
								//IL_00fa: Expected O, but got Unknown
								RectTransform component = ((Component)b).GetComponent<RectTransform>();
								float num = listElement.sizeDelta.x;
								if (spawnToggles)
								{
									num -= 40f;
								}
								component.sizeDelta = new Vector2(num, 35f);
								Text componentInChildren = ((Component)b).GetComponentInChildren<Text>();
								componentInChildren.text = metadata.Title + " | " + metadata.GetTimeString() + " | " + metadata.GetFileName();
								UnityAction val7 = default(UnityAction);
								((UnityEvent)b.onClick).AddListener((UnityAction)delegate
								{
									//IL_007e: Unknown result type (might be due to invalid IL or missing references)
									//IL_0342: Unknown result type (might be due to invalid IL or missing references)
									//IL_0423: Unknown result type (might be due to invalid IL or missing references)
									//IL_0428: Unknown result type (might be due to invalid IL or missing references)
									//IL_042b: Expected O, but got Unknown
									//IL_0430: Expected O, but got Unknown
									//IL_049f: Unknown result type (might be due to invalid IL or missing references)
									//IL_04a9: Expected O, but got Unknown
									//IL_0515: Unknown result type (might be due to invalid IL or missing references)
									//IL_051a: Unknown result type (might be due to invalid IL or missing references)
									//IL_051d: Expected O, but got Unknown
									//IL_0522: Expected O, but got Unknown
									((Component)runList).gameObject.SetActive(false);
									((Component)runEditMenu).gameObject.SetActive(true);
									bool flag = metadata.SteamID == SteamClient.SteamId.Value;
									bool isDirty = false;
									runEditTitle.SetTextWithoutNotify(metadata.Title);
									((Selectable)runEditTitle).interactable = flag;
									string updatedTitle = metadata.Title;
									((UnityEventBase)runEditTitle.onEndEdit).RemoveAllListeners();
									if (flag)
									{
										((UnityEvent<string>)(object)runEditTitle.onEndEdit).AddListener((UnityAction<string>)delegate(string v)
										{
											updatedTitle = v;
											isDirty = true;
										});
									}
									runEditDescription.SetTextWithoutNotify(metadata.Description);
									((Selectable)runEditDescription).interactable = flag;
									string updatedDesc = metadata.Description;
									((UnityEventBase)runEditDescription.onEndEdit).RemoveAllListeners();
									if (flag)
									{
										((UnityEvent<string>)(object)runEditDescription.onEndEdit).AddListener((UnityAction<string>)delegate(string v)
										{
											updatedDesc = v;
											isDirty = true;
										});
									}
									runEditLevelName.text = metadata.LevelName;
									runEditDate.text = metadata.DateCreated.ToString("MM/dd/yyyy hh:mm:ss");
									Friend val8 = default(Friend);
									((Friend)(ref val8))..ctor(SteamId.op_Implicit(metadata.SteamID));
									runEditRunnerName.text = ((Friend)(ref val8)).Name;
									((UnityEventBase)backButton.onClick).RemoveAllListeners();
									ButtonClickedEvent onClick = backButton.onClick;
									UnityAction obj = val5;
									if (obj == null)
									{
										UnityAction val9 = delegate
										{
											((Component)runEditMenu).gameObject.SetActive(false);
											((Component)runList).gameObject.SetActive(true);
										};
										UnityAction val10 = val9;
										val5 = val9;
										obj = val10;
									}
									((UnityEvent)onClick).AddListener(obj);
									((UnityEventBase)saveButton.onClick).RemoveAllListeners();
									if (flag)
									{
										((UnityEvent)saveButton.onClick).AddListener((UnityAction)delegate
										{
											if (isDirty)
											{
												isDirty = false;
												metadata.Title = updatedTitle;
												metadata.Description = updatedDesc;
												GhostFileManager.UpdateMetadata(metadata);
											}
										});
									}
									((UnityEventBase)deleteButton.onClick).RemoveAllListeners();
									ButtonClickedEvent onClick2 = deleteButton.onClick;
									UnityAction obj2 = val7;
									if (obj2 == null)
									{
										UnityAction val11 = delegate
										{
											GhostFileManager.DeleteRun(metadata);
											((Component)runList).gameObject.SetActive(true);
											((Component)runEditMenu).gameObject.SetActive(false);
											metadatas.Remove(metadata);
											Object.Destroy((Object)(object)((Component)b).gameObject);
											Canvas.ForceUpdateCanvases();
										};
										UnityAction val10 = val11;
										val7 = val11;
										obj2 = val10;
									}
									((UnityEvent)onClick2).AddListener(obj2);
									runTime.text = "TIME: " + metadata.GetTimeString();
									runStyle.text = $"STYLE: {metadata.StatGoal.Style}";
									runKills.text = $"KILLS: {metadata.StatGoal.Kills}";
									runDeaths.text = $"DEATHS: {metadata.StatGoal.Deaths}";
								});
							});
						});
					}
				}
			});
		}

		public ConfiggableAttribute GetDescriptor()
		{
			return configgableAttribute;
		}

		public void OnMenuClose()
		{
		}

		public void OnMenuOpen()
		{
		}
	}
	public static class ThemeHelper
	{
		public static readonly Color PColorOn = new Color(255f, 119f, 0f, 255f);

		public static readonly Color PColorOff = new Color(191f, 191f, 191f, 150f);
	}
	public class AssetLoader
	{
		private Dictionary<string, Object> loadedAssets = new Dictionary<string, Object>();

		public AssetBundle Bundle { get; }

		public AssetLoader(AssetBundle bundle)
		{
			Bundle = bundle;
		}

		public AssetLoader(byte[] bundleBytes)
		{
			Bundle = AssetBundle.LoadFromMemory(bundleBytes);
		}

		public AssetLoader(string filePath)
		{
			Bundle = AssetBundle.LoadFromFile(filePath);
		}

		public T LoadAsset<T>(string assetName) where T : Object
		{
			if (loadedAssets.ContainsKey(assetName))
			{
				return (T)(object)loadedAssets[assetName];
			}
			T val = Bundle.LoadAsset<T>(assetName);
			if ((Object)(object)val == (Object)null)
			{
				return default(T);
			}
			loadedAssets.Add(assetName, (Object)(object)val);
			return val;
		}

		public T[] LoadAllAssets<T>() where T : Object
		{
			T[] array = Bundle.LoadAllAssets<T>();
			T[] array2 = array;
			foreach (T val in array2)
			{
				if (!((Object)(object)val == (Object)null) && !loadedAssets.ContainsKey(((Object)val).name))
				{
					loadedAssets.Add(((Object)val).name, (Object)(object)val);
				}
			}
			return array;
		}

		public void Unload(bool unloadAllLoadedObjects = true)
		{
			Bundle.Unload(unloadAllLoadedObjects);
		}
	}
	public interface IEZPZTracker
	{
		void SetStatGoal(StatGoal goal);
	}
	public interface IUIEditable
	{
		void StartEditMode();

		void EndEditMode();
	}
	[Serializable]
	public struct StatGoal
	{
		public int Difficulty;

		public int Kills;

		public float Seconds;

		public int Deaths;

		public int Style;

		public bool NotEmpty()
		{
			return Kills > 0 || Seconds > 0f || Deaths > 0 || Style > 0;
		}

		public bool IsFailed()
		{
			if (MonoSingleton<NewMovement>.Instance.dead)
			{
				if (MonoSingleton<StatsManager>.Instance.restarts + 1 > Deaths)
				{
					return true;
				}
			}
			else if (MonoSingleton<StatsManager>.Instance.restarts > Deaths)
			{
				return true;
			}
			if (MonoSingleton<StatsManager>.Instance.seconds > Seconds)
			{
				return true;
			}
			if (MonoSingleton<StatsManager>.Instance.infoSent)
			{
				if (MonoSingleton<StatsManager>.Instance.kills < Kills)
				{
					return true;
				}
				if (MonoSingleton<StatsManager>.Instance.stylePoints < Style)
				{
					return true;
				}
			}
			return false;
		}

		public bool IsComplete()
		{
			if (MonoSingleton<StatsManager>.Instance.seconds > Seconds)
			{
				return false;
			}
			if (MonoSingleton<StatsManager>.Instance.restarts > Deaths)
			{
				return false;
			}
			if (MonoSingleton<StatsManager>.Instance.stylePoints < Style)
			{
				return false;
			}
			if (MonoSingleton<StatsManager>.Instance.kills < Kills)
			{
				return false;
			}
			return true;
		}
	}
}
namespace EasyPZ.Properties
{
	[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
	[DebuggerNonUserCode]
	[CompilerGenerated]
	internal class EasyPZResources
	{
		private static ResourceManager resourceMan;

		private static CultureInfo resourceCulture;

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		internal static ResourceManager ResourceManager
		{
			get
			{
				if (resourceMan == null)
				{
					ResourceManager resourceManager = new ResourceManager("EasyPZ.Properties.Resources", typeof(EasyPZResources).Assembly);
					resourceMan = resourceManager;
				}
				return resourceMan;
			}
		}

		[EditorBrowsable(EditorBrowsableState.Advanced)]
		internal static CultureInfo Culture
		{
			get
			{
				return resourceCulture;
			}
			set
			{
				resourceCulture = value;
			}
		}

		internal static byte[] EasyPZ
		{
			get
			{
				object @object = ResourceManager.GetObject("EasyPZ", resourceCulture);
				return (byte[])@object;
			}
		}

		internal EasyPZResources()
		{
		}
	}
}
namespace EasyPZ.Patches
{
	[HarmonyPatch(typeof(CanvasController))]
	public static class InstanceUI
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		public static void OnAwake(CanvasController __instance)
		{
			RectTransform component = ((Component)__instance).GetComponent<RectTransform>();
			if ((Object)(object)component == (Object)null)
			{
				Debug.LogError((object)"EZPZ: Canvas controller patch issue!, RectTransform could not be found!");
			}
			else
			{
				InstanceElements(component);
			}
		}

		private static void InstanceElements(RectTransform root)
		{
			Object.Instantiate<GameObject>(Prefabs.TrackerManager, (Transform)(object)root);
			Object.Instantiate<GameObject>(Prefabs.RunManagerMenu, (Transform)(object)root);
			Object.Instantiate<GameObject>(Prefabs.GhostSavedNotifier, (Transform)(object)root);
		}
	}
}
namespace EasyPZ.UIEdit
{
	public class MovableWindow : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler
	{
		[SerializeField]
		private RectTransform target;

		private Canvas canvas;

		public void OnBeginDrag(PointerEventData eventData)
		{
			if (((Behaviour)this).enabled)
			{
				canvas = ((Component)target).GetComponentInParent<Canvas>();
			}
		}

		public void OnDrag(PointerEventData eventData)
		{
			//IL_0017: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (((Behaviour)this).enabled)
			{
				RectTransform obj = target;
				obj.anchoredPosition += eventData.delta / canvas.scaleFactor;
			}
		}
	}
	public class WindowScalar : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler
	{
		[SerializeField]
		private RectTransform target;

		[SerializeField]
		private Vector2 maxSize;

		[SerializeField]
		private Vector2 minSize;

		[SerializeField]
		private TextAnchor scaleDirection;

		private Canvas canvas;

		public void OnBeginDrag(PointerEventData eventData)
		{
			canvas = ((Component)target).GetComponentInParent<Canvas>();
		}

		public void OnDrag(PointerEventData eventData)
		{
			//IL_0003: 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_000e: 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_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_002f: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_0065: 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)
			Vector2 val = Vector2.Scale(GetMultiplier(scaleDirection), eventData.delta / canvas.scaleFactor);
			Vector2 val2 = target.sizeDelta + val;
			val2.x = Mathf.Clamp(val2.x, minSize.x, maxSize.x);
			val2.y = Mathf.Clamp(val2.y, minSize.y, maxSize.y);
			target.sizeDelta = val2;
		}

		private Vector2 GetMultiplier(TextAnchor alignment)
		{
			//IL_0001: 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_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: 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_002f: Expected I4, but got Unknown
			//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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			return (Vector2)((int)alignment switch
			{
				0 => new Vector2(-1f, 1f), 
				2 => Vector2.one, 
				6 => -Vector2.one, 
				8 => new Vector2(1f, -1f), 
				7 => new Vector2(0f, -1f), 
				1 => new Vector2(0f, 1f), 
				4 => Vector2.zero, 
				3 => new Vector2(-1f, 0f), 
				5 => new Vector2(1f, 0f), 
				_ => Vector2.zero, 
			});
		}
	}
}
namespace EasyPZ.Components
{
	public class SpeedLimiter : LevelSessionBehaviour
	{
		[Configgable("Extras/Speed Limiter", "Speed Limit Enabled", 0, null)]
		private static ConfigToggle enableSpeedLimit = new ConfigToggle(false);

		[Configgable("Extras/Speed Limiter", "Min Speed", 0, null)]
		private static ConfigInputField<float> minSpeed = new ConfigInputField<float>(10f, (Func<float, bool>)null, (Func<string, ValueTuple<bool, float>>)null);

		[Configgable("Extras/Speed Limiter", "Max Speed", 0, null)]
		private static ConfigInputField<float> maxSpeed = new ConfigInputField<float>(500f, (Func<float, bool>)null, (Func<string, ValueTuple<bool, float>>)null);

		[Configgable("Extras/Speed Limiter", "Forgiveness Time", 0, null)]
		private static ConfigInputField<float> forgivenessTime = new ConfigInputField<float>(1.5f, (Func<float, bool>)null, (Func<string, ValueTuple<bool, float>>)null);

		private float timeSpeedLimitBroken;

		protected override void OnSessionUpdate()
		{
			//IL_0021: 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)
			if (!((ConfigValueElement<bool>)(object)enableSpeedLimit).Value)
			{
				return;
			}
			Vector3 velocity = MonoSingleton<NewMovement>.Instance.rb.velocity;
			float magnitude = ((Vector3)(ref velocity)).magnitude;
			if (magnitude > ((ConfigValueElement<float>)(object)maxSpeed).Value || magnitude < ((ConfigValueElement<float>)(object)minSpeed).Value)
			{
				timeSpeedLimitBroken += Time.deltaTime;
				if (timeSpeedLimitBroken > ((ConfigValueElement<float>)(object)forgivenessTime).Value)
				{
					MonoSingleton<OptionsManager>.Instance.RestartMission();
				}
			}
			else
			{
				timeSpeedLimitBroken = 0f;
			}
		}

		protected override void OnStartSession()
		{
		}

		protected override void OnStopSession()
		{
		}
	}
	public class GhostManager : LevelSessionBehaviour
	{
		[Configgable("Ghosts/Playback", "Max Ghosts", 0, "Hard cap on ghosts to spawn regardless of selected amount.")]
		private static ConfigInputField<int> maxGhosts = new ConfigInputField<int>(3, (Func<int, bool>)null, (Func<string, ValueTuple<bool, int>>)null);

		[Configgable("Ghosts/Playback", "Ghosts Enabled", 0, null)]
		private static ConfigToggle ghostsEnabled = new ConfigToggle(true);

		[Configgable("Ghosts/Playback", "Ghost Opacity", 0, null)]
		private static FloatSlider ghostOpacity = new FloatSlider(1f, 0f, 1f);

		[Configgable("Ghosts/Playback", "Ghost Spawn Order", 0, "Changes how the selection of max ghosts are spawned.")]
		private static ConfigDropdown<GhostSpawnOrderType> ghostSpawningPattern = new ConfigDropdown<GhostSpawnOrderType>((GhostSpawnOrderType[])Enum.GetValues(typeof(GhostSpawnOrderType)), (string[])null, 0);

		private const string ghostSpawnPatternDescription = "Changes how the selection of max ghosts are spawned.";

		private static GameObject ghostPlayerPrefab;

		private List<GhostPlayer> ghostPlayers;

		private List<SessionRecording> loadedRecordings;

		private float timeStarted;

		private static GhostManager instance;

		private static Dictionary<string, bool> enabledGhosts = new Dictionary<string, bool>();

		private static GameObject GhostPlayerPrefab
		{
			get
			{
				if ((Object)(object)ghostPlayerPrefab == (Object)null)
				{
					ghostPlayerPrefab = BuildGhostPlayerPrefab();
				}
				return ghostPlayerPrefab;
			}
		}

		private bool spawnedGhosts => ghostPlayers != null;

		private void Awake()
		{
			instance = this;
		}

		public static bool IsGhostEnabled(string id)
		{
			if (!enabledGhosts.ContainsKey(id))
			{
				enabledGhosts.Add(id, value: true);
				return true;
			}
			return enabledGhosts[id];
		}

		public static void SetGhostEnabled(string id, bool enabled)
		{
			if (!enabledGhosts.ContainsKey(id))
			{
				enabledGhosts.Add(id, enabled);
				return;
			}
			enabledGhosts[id] = enabled;
			if ((Object)(object)instance != (Object)null)
			{
				instance.ResetGhosts();
			}
		}

		protected override void OnSessionUpdate()
		{
		}

		public static void PreloadGhostPrefab()
		{
			if (!((Object)(object)ghostPlayerPrefab != (Object)null))
			{
				ghostPlayerPrefab = BuildGhostPlayerPrefab();
			}
		}

		private void Start()
		{
			ConfigToggle obj = ghostsEnabled;
			((ConfigValueElement<bool>)(object)obj).OnValueChanged = (Action<bool>)Delegate.Combine(((ConfigValueElement<bool>)(object)obj).OnValueChanged, new Action<bool>(SetGhostsEnabled));
			ConfigInputField<int> obj2 = maxGhosts;
			((ConfigValueElement<int>)(object)obj2).OnValueChanged = (Action<int>)Delegate.Combine(((ConfigValueElement<int>)(object)obj2).OnValueChanged, new Action<int>(ResetGhostsFromEvent));
			ConfigDropdown<GhostSpawnOrderType> obj3 = ghostSpawningPattern;
			((ConfigValueElement<GhostSpawnOrderType>)(object)obj3).OnValueChanged = (Action<GhostSpawnOrderType>)Delegate.Combine(((ConfigValueElement<GhostSpawnOrderType>)(object)obj3).OnValueChanged, new Action<GhostSpawnOrderType>(ResetGhostsFromEvent));
			SetGhostsEnabled(((ConfigValueElement<bool>)(object)ghostsEnabled).Value);
		}

		private void LoadRecordings()
		{
			string currentScene = SceneHelper.CurrentScene;
			string path = Path.Combine(((ConfigValueElement<string>)(object)Paths.ghostRecordingPath).Value, currentScene);
			if (!Directory.Exists(path))
			{
				loadedRecordings = new List<SessionRecording>();
				return;
			}
			DirectoryInfo directoryInfo = new DirectoryInfo(path);
			List<SessionRecording> list = new List<SessionRecording>();
			FileInfo[] files = directoryInfo.GetFiles("*.ukrun", SearchOption.TopDirectoryOnly);
			foreach (FileInfo fileInfo in files)
			{
				try
				{
					SessionRecording sessionRecording = SessionRecording.LoadFromBytes(File.ReadAllBytes(fileInfo.FullName));
					sessionRecording.Metadata.LocatedFilePath = fileInfo.FullName;
					Debug.Log((object)$"Loaded recording {fileInfo.Name} with {sessionRecording.frames.Count} frames");
					list.Add(sessionRecording);
				}
				catch (Exception ex)
				{
					Debug.LogError((object)ex);
				}
			}
			loadedRecordings = list;
		}

		protected override void OnStartSession()
		{
			timeStarted = Time.time;
			if (((ConfigValueElement<bool>)(object)ghostsEnabled).Value)
			{
				PlayGhosts();
			}
		}

		protected override void OnStopSession()
		{
			DisposeGhosts();
		}

		private void SetGhostsEnabled(bool enabled)
		{
			if (!enabled)
			{
				if (spawnedGhosts)
				{
					DisposeGhosts();
				}
				return;
			}
			if (!spawnedGhosts)
			{
				SpawnGhosts();
			}
			if (started)
			{
				PlayGhosts();
			}
		}

		private void PlayGhosts()
		{
			foreach (GhostPlayer ghostPlayer in ghostPlayers)
			{
				ghostPlayer.Play(timeStarted);
			}
		}

		private void ResetGhostsFromEvent<T>(T _)
		{
			ResetGhosts();
		}

		private void ResetGhosts()
		{
			if (spawnedGhosts && ((ConfigValueElement<bool>)(object)ghostsEnabled).Value)
			{
				DisposeGhosts();
				SpawnGhosts();
				if (started)
				{
					PlayGhosts();
				}
			}
		}

		private void SpawnGhosts()
		{
			ghostPlayers = new List<GhostPlayer>();
			if (loadedRecordings == null)
			{
				LoadRecordings();
			}
			foreach (SessionRecording item in SelectRecordings())
			{
				SpawnGhost(item);
			}
		}

		private IEnumerable<SessionRecording> SelectRecordings()
		{
			if (loadedRecordings.Count == 0)
			{
				return Enumerable.Empty<SessionRecording>();
			}
			IEnumerable<SessionRecording> source = loadedRecordings.Where((SessionRecording x) => enabledGhosts.ContainsKey(x.Metadata.LocatedFilePath) && enabledGhosts[x.Metadata.LocatedFilePath]);
			if (source.Count() == 0)
			{
				return Enumerable.Empty<SessionRecording>();
			}
			switch (((ConfigValueElement<GhostSpawnOrderType>)(object)ghostSpawningPattern).Value)
			{
			case GhostSpawnOrderType.Fastest:
				source = source.OrderBy((SessionRecording x) => x.GetTotalTime());
				break;
			case GhostSpawnOrderType.Slowest:
				source = source.OrderByDescending((SessionRecording x) => x.GetTotalTime());
				break;
			case GhostSpawnOrderType.MostRecent:
				source = source.OrderByDescending((SessionRecording x) => x.Metadata.DateCreated.Ticks);
				break;
			}
			int count = Mathf.Min(((ConfigValueElement<int>)(object)maxGhosts).Value, source.Count());
			return source.Take(count);
		}

		private void SpawnGhost(SessionRecording recording)
		{
			GameObject val = Object.Instantiate<GameObject>(GhostPlayerPrefab);
			val.SetActive(true);
			GhostPlayer ghostPlayer = val.AddComponent<GhostPlayer>();
			ghostPlayer.SetRecording(recording);
			ghostPlayers.Add(ghostPlayer);
		}

		private void DisposeGhosts()
		{
			foreach (GhostPlayer ghostPlayer in ghostPlayers)
			{
				if ((Object)(object)ghostPlayer != (Object)null)
				{
					ghostPlayer.Dispose();
				}
			}
			ghostPlayers = null;
		}

		private void OnDestroy()
		{
			ConfigToggle obj = ghostsEnabled;
			((ConfigValueElement<bool>)(object)obj).OnValueChanged = (Action<bool>)Delegate.Remove(((ConfigValueElement<bool>)(object)obj).OnValueChanged, new Action<bool>(SetGhostsEnabled));
			ConfigInputField<int> obj2 = maxGhosts;
			((ConfigValueElement<int>)(object)obj2).OnValueChanged = (Action<int>)Delegate.Remove(((ConfigValueElement<int>)(object)obj2).OnValueChanged, new Action<int>(ResetGhostsFromEvent));
			ConfigDropdown<GhostSpawnOrderType> obj3 = ghostSpawningPattern;
			((ConfigValueElement<GhostSpawnOrderType>)(object)obj3).OnValueChanged = (Action<GhostSpawnOrderType>)Delegate.Remove(((ConfigValueElement<GhostSpawnOrderType>)(object)obj3).OnValueChanged, new Action<GhostSpawnOrderType>(ResetGhostsFromEvent));
		}

		private static GameObject BuildGhostPlayerPrefab()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_0130: Expected O, but got Unknown
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Addressables.LoadAssetAsync<GameObject>((object)"Assets/Prefabs/Enemies/V2.prefab").WaitForCompletion();
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogError((object)"Could not find V2 prefab");
				return null;
			}
			try
			{
				GameObject val2 = Object.Instantiate<GameObject>(val);
				RemoveAllComponent<V2>(val2);
				RemoveAllComponent<Rigidbody>(val2);
				RemoveAllComponent<Collider>(val2);
				RemoveAllComponent<Machine>(val2);
				RemoveAllComponent<NavMeshAgent>(val2);
				RemoveAllComponent<EnemyIdentifier>(val2);
				RemoveAllComponent<EnemyIdentifierIdentifier>(val2);
				RemoveAllComponent<GroundCheckEnemy>(val2);
				RemoveAllComponent<BulletCheck>(val2);
				RemoveAllComponent<EnemySimplifier>(val2);
				RemoveAllComponent<EnemyShotgun>(val2);
				RemoveAllComponent<EnemyNailgun>(val2);
				RemoveAllComponent<EnemyRevolver>(val2);
				RemoveAllComponent<V2AnimationController>(val2);
				List<Renderer> list = new List<Renderer>();
				SkinnedMeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<SkinnedMeshRenderer>(true);
				MeshRenderer[] componentsInChildren2 = val2.GetComponentsInChildren<MeshRenderer>(true);
				list.AddRange((IEnumerable<Renderer>)(object)componentsInChildren);
				list.AddRange((IEnumerable<Renderer>)(object)componentsInChildren2);
				Material ghostMaterial = Prefabs.GhostMaterial;
				List<Material> createdMaterials = new List<Material>();
				float value = ((ConfigValueElement<float>)(object)ghostOpacity).Value;
				for (int i = 0; i < list.Count; i++)
				{
					Material[] array = (Material[])(object)new Material[list[i].sharedMaterials.Length];
					for (int j = 0; j < list[i].sharedMaterials.Length; j++)
					{
						Material val3 = new Material(ghostMaterial);
						createdMaterials.Add(val3);
						Color color = val3.color;
						color.a = value;
						val3.color = color;
						array[j] = val3;
						Texture texture = list[i].sharedMaterials[j].GetTexture("_MainTex");
						array[j].SetTexture("_MainTex", texture);
					}
					list[i].sharedMaterials = array;
				}
				FloatSlider obj = ghostOpacity;
				((ConfigValueElement<float>)(object)obj).OnValueChanged = (Action<float>)Delegate.Combine(((ConfigValueElement<float>)(object)obj).OnValueChanged, (Action<float>)delegate(float v)
				{
					//IL_001a: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0029: Unknown result type (might be due to invalid IL or missing references)
					foreach (Material item in createdMaterials)
					{
						Color color2 = item.color;
						color2.a = v;
						item.color = color2;
					}
				});
				((Object)val2).name = "PlayerGhost";
				((Object)val2).hideFlags = (HideFlags)61;
				val2.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)val2);
				return val2;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)"Error creating Player Ghost Prefab.");
				Debug.LogException(ex);
				return null;
			}
		}

		private static void RemoveAllComponent<T>(GameObject go) where T : Component
		{
			T[] componentsInChildren = go.GetComponentsInChildren<T>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				T val = componentsInChildren[i];
				componentsInChildren[i] = default(T);
				Object.Destroy((Object)(object)val);
			}
		}
	}
	public enum GhostSpawnOrderType
	{
		Fastest,
		Slowest,
		MostRecent
	}
	public class GhostNotifier : MonoBehaviour
	{
		private static GhostNotifier instance;

		private Animator animator;

		private void Awake()
		{
			instance = this;
			animator = ((Component)this).GetComponentInChildren<Animator>();
		}

		private void ShowNotif()
		{
			animator.Play("Show");
		}

		public static void Notify()
		{
			if (!((Object)(object)instance == (Object)null))
			{
				instance.ShowNotif();
			}
		}
	}
	public class GhostPlayer : MonoBehaviour, IDisposable
	{
		private SessionRecording recording;

		private Animator animator;

		private Transform[] rotationTransforms;

		private float timeStarted;

		private bool isPlaying;

		private int lastAnimationState = 0;

		public void SetRecording(SessionRecording recording)
		{
			this.recording = recording;
		}

		private void Awake()
		{
			animator = (from x in ((Component)this).GetComponentsInChildren<Animator>(true)
				where ((Object)x).name == "v2_combined"
				select x).FirstOrDefault();
			rotationTransforms = (Transform[])(object)new Transform[2];
			rotationTransforms[0] = (from x in ((Component)this).GetComponentsInChildren<Transform>(true)
				where ((Object)x).name == "spine.006"
				select x).FirstOrDefault();
			rotationTransforms[1] = (from x in ((Component)this).GetComponentsInChildren<Transform>(true)
				where ((Object)x).name == "upper_arm.R"
				select x).FirstOrDefault();
			TrailRenderer val = ((Component)this).GetComponentsInChildren<TrailRenderer>(true).FirstOrDefault();
			if ((Object)(object)val != (Object)null)
			{
				((Renderer)val).enabled = false;
			}
		}

		private void Start()
		{
			InstanceNamePlate();
		}

		private void InstanceNamePlate()
		{
			//IL_0022: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			string text = "";
			try
			{
				if (!SteamClient.IsValid)
				{
					throw new Exception("Steam not valid or not connected!");
				}
				Friend val = new Friend(SteamId.op_Implicit(recording.Metadata.SteamID));
				text = ((Friend)(ref val)).Name;
				Debug.Log((object)("Created Ghost " + text));
				GameObject gameObject = ((Component)this).gameObject;
				((Object)gameObject).name = ((Object)gameObject).name + "(" + text + ")";
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
				Debug.LogError((object)"Unable to name ghost :(");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(Prefabs.PlayerNameplate, ((Component)this).transform);
			val2.transform.localPosition = new Vector3(0f, 3.854f, 0f);
			val2.transform.localEulerAngles = new Vector3(0f, 0f, 0f);
			Text componentInChildren = val2.GetComponentInChildren<Text>();
			componentInChildren.text = text;
		}

		private void Update()
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			if (!isPlaying || recording == null)
			{
				return;
			}
			float num = Time.time - timeStarted;
			SessionRecordingFrame[] nearestTwoFrames = recording.GetNearestTwoFrames(num);
			if (nearestTwoFrames == null)
			{
				return;
			}
			if (nearestTwoFrames[1].time < num)
			{
				Dispose();
				return;
			}
			float num2 = Mathf.InverseLerp(nearestTwoFrames[0].time, nearestTwoFrames[1].time, num);
			int num3 = ((num2 > 0.5f) ? nearestTwoFrames[1].animation : nearestTwoFrames[0].animation);
			Vector3 val = Vector3.Lerp(nearestTwoFrames[0].position, nearestTwoFrames[1].position, num2);
			if (num3 == 1 || num3 == 0)
			{
				val += -Vector3.up * 1.15f;
			}
			float num4 = Mathf.LerpAngle(nearestTwoFrames[0].rotation.y, nearestTwoFrames[1].rotation.y, num2);
			float num5 = Mathf.LerpAngle(nearestTwoFrames[0].rotation.x, nearestTwoFrames[1].rotation.x, num2);
			((Component)this).transform.position = val;
			((Component)this).transform.eulerAngles = new Vector3(0f, num4, 0f);
			for (int i = 0; i < rotationTransforms.Length; i++)
			{
				if (!((Object)(object)rotationTransforms[i] == (Object)null))
				{
					rotationTransforms[i].eulerAngles = new Vector3(num5, 0f, 0f);
				}
			}
			SetAnimation(num3);
		}

		public void Play(float timeStarted)
		{
			this.timeStarted = timeStarted;
			isPlaying = true;
		}

		public void SetCurrentTime(float time)
		{
			timeStarted = Time.time - time;
		}

		public void Stop()
		{
			isPlaying = false;
		}

		private void SetAnimation(int animationState)
		{
			if (lastAnimationState != animationState && !((Object)(object)animator == (Object)null))
			{
				switch (animationState)
				{
				case 0:
					animator.SetLayerWeight(1, 0f);
					animator.SetBool("RunningForward", false);
					animator.SetBool("InAir", false);
					animator.SetBool("Sliding", false);
					break;
				case 1:
					animator.SetLayerWeight(1, 1f);
					animator.SetBool("RunningForward", true);
					animator.SetBool("InAir", false);
					animator.SetBool("Sliding", false);
					break;
				case 2:
					animator.SetLayerWeight(1, 0f);
					animator.Play("Slide", 0, 0f);
					animator.SetBool("RunningForward", false);
					animator.SetBool("InAir", false);
					animator.SetBool("Sliding", true);
					break;
				case 3:
					animator.SetLayerWeight(1, 0f);
					animator.SetBool("RunningForward", false);
					animator.SetBool("InAir", true);
					animator.SetBool("Sliding", false);
					break;
				}
			}
		}

		public void Dispose()
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}
	public class SessionRecorder : LevelSessionBehaviour
	{
		private SessionRecording recording;

		private float timeStartedRecording;

		[Configgable("Ghosts/Recording", "Recording Frame Rate", 0, "The frame rate at which the ghost will be recorded. Higher frame rates will result in smoother playback, but larger file sizes. Frames can only be recorded as fast as your system can render them, so setting this higher than your max fps won't record additional frames.")]
		private static ConfigInputField<int> recorderFrameRate = new ConfigInputField<int>(16, (Func<int, bool>)null, (Func<string, ValueTuple<bool, int>>)null);

		private const string frameRateDescription = "The frame rate at which the ghost will be recorded. Higher frame rates will result in smoother playback, but larger file sizes. Frames can only be recorded as fast as your system can render them, so setting this higher than your max fps won't record additional frames.";

		[Configgable("Ghosts/Recording", "Recording Enabled", 0, null)]
		private static ConfigToggle recordingEnabled = new ConfigToggle(true);

		private bool recordCurrentSession = false;

		private float lastFrameTime;

		private bool cheatsUsedInSession;

		private bool assistsUsedInSession;

		private static float frameTime => 1f / (float)((ConfigValueElement<int>)(object)recorderFrameRate).Value;

		protected override void OnSessionUpdate()
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			if (recordCurrentSession && !(Time.time - lastFrameTime < frameTime))
			{
				lastFrameTime = Time.time;
				if (MonoSingleton<AssistController>.Instance.cheatsEnabled)
				{
					cheatsUsedInSession = true;
				}
				if (MonoSingleton<AssistController>.Instance.majorEnabled)
				{
					assistsUsedInSession = true;
				}
				recording.frames.Add(new SessionRecordingFrame
				{
					position = ((Component)MonoSingleton<NewMovement>.Instance).transform.position,
					rotation = new Vector2(((Component)MonoSingleton<CameraController>.Instance).transform.localEulerAngles.x, ((Component)MonoSingleton<CameraController>.Instance).transform.eulerAngles.y),
					animation = GetAnimationState(),
					time = Time.time - timeStartedRecording
				});
			}
		}

		private int GetAnimationState()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			MovementActions movement = MonoSingleton<InputManager>.Instance.InputSource.Actions.Movement;
			Vector2 val = ((MovementActions)(ref movement)).Move.ReadValue<Vector2>();
			movement = MonoSingleton<InputManager>.Instance.InputSource.Actions.Movement;
			bool flag = ((MovementActions)(ref movement)).Slide.IsPressed();
			bool onGround = MonoSingleton<NewMovement>.Instance.gc.onGround;
			if (flag)
			{
				return 2;
			}
			if (!onGround)
			{
				return 3;
			}
			if (val.y > 0f)
			{
				return 1;
			}
			return 0;
		}

		protected override void OnStartSession()
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			recordCurrentSession = ((ConfigValueElement<bool>)(object)recordingEnabled).Value;
			if (!recordCurrentSession)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			timeStartedRecording = Time.time;
			recording = new SessionRecording();
			recording.Metadata.DateCreated = DateTime.Now;
			recording.Metadata.ModVersion = "3.0.0";
			recording.Metadata.GameVersion = Application.version;
			if (SteamClient.IsValid)
			{
				recording.Metadata.SteamID = SteamClient.SteamId.Value;
			}
			else
			{
				recording.Metadata.SteamID = 0uL;
			}
			recording.Metadata.Difficulty = MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0);
			recording.Metadata.LevelName = SceneHelper.CurrentScene;
			recording.Metadata.Description = "My run of " + recording.Metadata.LevelName;
			recording.Metadata.Title = "My " + recording.Metadata.LevelName + " run";
			Debug.Log((object)"Ghost Recording Started");
		}

		protected override void OnStopSession()
		{
			if (recordCurrentSession)
			{
				recording.Metadata.NoDamage = !MonoSingleton<StatsManager>.Instance.tookDamage;
				recording.Metadata.CheatsUsed = cheatsUsedInSession;
				recording.Metadata.MajorAssistsUsed = assistsUsedInSession;
				Debug.Log((object)"Ghost Recording Stopped");
				recording.SetStats(new StatGoal
				{
					Deaths = MonoSingleton<StatsManager>.Instance.restarts,
					Kills = MonoSingleton<StatsManager>.Instance.kills,
					Style = MonoSingleton<StatsManager>.Instance.stylePoints,
					Seconds = MonoSingleton<StatsManager>.Instance.seconds
				});
				SaveRecording();
				GhostNotifier.Notify();
			}
		}

		private void SaveRecording()
		{
			recording.FixTimeOffset();
			string currentScene = SceneHelper.CurrentScene;
			string text = Path.Combine(((ConfigValueElement<string>)(object)Paths.ghostRecordingPath).Value, currentScene);
			if (!Directory.Exists(text))
			{
				Directory.CreateDirectory(text);
			}
			string text2 = DateTime.Now.ToString("yyyy-MM-dd-mm-ss");
			string text3 = ".ukrun";
			string text4 = Path.Combine(text, text2 + text3);
			Debug.Log((object)("Saved new ghost: " + text4));
			File.WriteAllBytes(text4, recording.ToBytes());
		}
	}
	public class SessionRecording
	{
		public const int FILE_TYPE_VERSION = 1;

		public int fileTypeVersion = 1;

		public SessionRecordingMetadata Metadata;

		public List<SessionRecordingFrame> frames;

		public float GetTotalTime()
		{
			return frames[frames.Count - 1].time;
		}

		public SessionRecording()
		{
			Metadata = new SessionRecordingMetadata();
			frames = new List<SessionRecordingFrame>();
		}

		public void SetStats(StatGoal stats)
		{
			Metadata.StatGoal = stats;
		}

		public void FixTimeOffset()
		{
			float time = frames[0].time;
			for (int i = 0; i < frames.Count; i++)
			{
				float time2 = frames[i].time;
				frames[i].time -= time;
			}
		}

		public SessionRecordingFrame[] GetNearestTwoFrames(float time)
		{
			SessionRecordingFrame[] array = new SessionRecordingFrame[2];
			if (frames.Count < 2)
			{
				return null;
			}
			float totalTime = GetTotalTime();
			if (time >= frames[frames.Count - 1].time)
			{
				return new SessionRecordingFrame[2]
				{
					frames[frames.Count - 2],
					frames[frames.Count - 1]
				};
			}
			if (time <= 0f)
			{
				return new SessionRecordingFrame[2]
				{
					frames[0],
					frames[1]
				};
			}
			for (int i = 1; i < frames.Count; i++)
			{
				SessionRecordingFrame sessionRecordingFrame = frames[i - 1];
				SessionRecordingFrame sessionRecordingFrame2 = frames[i];
				if (sessionRecordingFrame.time <= time && sessionRecordingFrame2.time >= time)
				{
					array[0] = sessionRecordingFrame;
					array[1] = sessionRecordingFrame2;
					return array;
				}
			}
			return null;
		}

		public static SessionRecording LoadFromBytes(byte[] data)
		{
			SessionRecording sessionRecording = new SessionRecording();
			using (MemoryStream input = new MemoryStream(data))
			{
				using BinaryReader binaryReader = new BinaryReader(input);
				sessionRecording.fileTypeVersion = binaryReader.ReadInt32();
				switch (sessionRecording.fileTypeVersion)
				{
				case 0:
					LoadFileTypeZero(sessionRecording, binaryReader);
					break;
				case 1:
					LoadFileTypeOne(sessionRecording, binaryReader);
					break;
				}
			}
			return sessionRecording;
		}

		private static void LoadFileTypeOne(SessionRecording recording, BinaryReader br)
		{
			recording.Metadata = SessionRecordingMetadata.ReadFileTypeOne(br);
			int num = br.ReadInt32();
			recording.frames = new List<SessionRecordingFrame>();
			for (int i = 0; i < num; i++)
			{
				recording.frames.Add(new SessionRecordingFrame().Read(br));
			}
		}

		private static void LoadFileTypeZero(SessionRecording recording, BinaryReader br)
		{
			recording.Metadata = SessionRecordingMetadata.ReadFileTypeZero(br);
			int num = br.ReadInt32();
			recording.frames = new List<SessionRecordingFrame>();
			for (int i = 0; i < num; i++)
			{
				recording.frames.Add(new SessionRecordingFrame().Read(br));
			}
		}

		public static SessionRecordingMetadata LoadMetadataOnlyFromFilePath(string filePath)
		{
			SessionRecordingMetadata result = null;
			if (!File.Exists(filePath))
			{
				throw new FileNotFoundException("File " + filePath + " does not exist.");
			}
			try
			{
				using FileStream input = new FileStream(filePath, FileMode.Open);
				using BinaryReader binaryReader = new BinaryReader(input);
				switch (binaryReader.ReadInt32())
				{
				case 0:
					result = SessionRecordingMetadata.ReadFileTypeZero(binaryReader);
					break;
				case 1:
					result = SessionRecordingMetadata.ReadFileTypeOne(binaryReader);
					break;
				}
				return result;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Failed to read file " + filePath));
				Debug.LogException(ex);
			}
			return null;
		}

		public byte[] ToBytes()
		{
			using MemoryStream memoryStream = new MemoryStream();
			using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream))
			{
				binaryWriter.Write(1);
				Metadata.TotalLength = GetTotalTime();
				Metadata.Write(binaryWriter);
				binaryWriter.Write(frames.Count);
				for (int i = 0; i < frames.Count; i++)
				{
					frames[i].Write(binaryWriter);
				}
			}
			return memoryStream.ToArray();
		}
	}
	public class SessionRecordingFrame
	{
		public Vector3 position;

		public Vector2 rotation;

		public int animation;

		public float time;

		public void Write(BinaryWriter w)
		{
			w.Write(time);
			w.Write(animation);
			w.Write(position.x);
			w.Write(position.y);
			w.Write(position.z);
			w.Write(rotation.x);
			w.Write(rotation.y);
		}

		public SessionRecordingFrame Read(BinaryReader r)
		{
			//IL_002c: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			time = r.ReadSingle();
			animation = r.ReadInt32();
			position = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
			rotation = new Vector2(r.ReadSingle(), r.ReadSingle());
			return this;
		}
	}
	public class SessionRecordingMetadata
	{
		public string LevelName;

		public int Difficulty;

		public ulong SteamID;

		public string Title;

		public string Description;

		public DateTime DateCreated;

		public string ModVersion;

		public string GameVersion;

		public float TotalLength;

		public bool CheatsUsed;

		public bool MajorAssistsUsed;

		public bool NoDamage;

		public string LocatedFilePath;

		public StatGoal StatGoal;

		public string GetFileName()
		{
			if (string.IsNullOrEmpty(LocatedFilePath))
			{
				return "FILE_PATH_INVALID";
			}
			return Path.GetFileNameWithoutExtension(LocatedFilePath);
		}

		public string GetTimeString(bool letters = false)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(StatGoal.Seconds);
			if (letters)
			{
				return $"{timeSpan.Minutes:D2}m:{timeSpan.Seconds:D2}s:{timeSpan.Milliseconds:D3}ms";
			}
			return $"{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}:{timeSpan.Milliseconds:D3}";
		}

		public static SessionRecordingMetadata ReadFileTypeOne(BinaryReader br)
		{
			SessionRecordingMetadata sessionRecordingMetadata = new SessionRecordingMetadata();
			sessionRecordingMetadata.LevelName = br.ReadString();
			sessionRecordingMetadata.Difficulty = br.ReadInt32();
			sessionRecordingMetadata.SteamID = br.ReadUInt64();
			sessionRecordingMetadata.Title = br.ReadString();
			sessionRecordingMetadata.Description = br.ReadString();
			sessionRecordingMetadata.DateCreated = new DateTime(br.ReadInt64());
			sessionRecordingMetadata.ModVersion = br.ReadString();
			sessionRecordingMetadata.GameVersion = br.ReadString();
			sessionRecordingMetadata.TotalLength = br.ReadSingle();
			sessionRecordingMetadata.CheatsUsed = br.ReadBoolean();
			sessionRecordingMetadata.MajorAssistsUsed = br.ReadBoolean();
			sessionRecordingMetadata.NoDamage = br.ReadBoolean();
			sessionRecordingMetadata.StatGoal = new StatGoal
			{
				Kills = br.ReadInt32(),
				Deaths = br.ReadInt32(),
				Style = br.ReadInt32(),
				Seconds = br.ReadSingle()
			};
			return sessionRecordingMetadata;
		}

		public static SessionRecordingMetadata ReadFileTypeZero(BinaryReader br)
		{
			SessionRecordingMetadata sessionRecordingMetadata = new SessionRecordingMetadata();
			sessionRecordingMetadata.LevelName = br.ReadString();
			sessionRecordingMetadata.Difficulty = br.ReadInt32();
			sessionRecordingMetadata.SteamID = br.ReadUInt64();
			sessionRecordingMetadata.Title = br.ReadString();
			sessionRecordingMetadata.Description = br.ReadString();
			sessionRecordingMetadata.DateCreated = new DateTime(br.ReadInt64());
			sessionRecordingMetadata.ModVersion = br.ReadString();
			sessionRecordingMetadata.GameVersion = br.ReadString();
			sessionRecordingMetadata.TotalLength = br.ReadSingle();
			sessionRecordingMetadata.StatGoal = new StatGoal
			{
				Kills = br.ReadInt32(),
				Deaths = br.ReadInt32(),
				Style = br.ReadInt32(),
				Seconds = br.ReadSingle()
			};
			return sessionRecordingMetadata;
		}

		public void Write(BinaryWriter bw)
		{
			bw.Write(LevelName);
			bw.Write(Difficulty);
			bw.Write(SteamID);
			bw.Write(Title);
			bw.Write(Description);
			bw.Write(DateCreated.Ticks);
			bw.Write(ModVersion);
			bw.Write(GameVersion);
			bw.Write(TotalLength);
			bw.Write(CheatsUsed);
			bw.Write(MajorAssistsUsed);
			bw.Write(NoDamage);
			bw.Write(StatGoal.Kills);
			bw.Write(StatGoal.Deaths);
			bw.Write(StatGoal.Style);
			bw.Write(StatGoal.Seconds);
		}

		public byte[] ToBytes()
		{
			using MemoryStream memoryStream = new MemoryStream();
			using (BinaryWriter bw = new BinaryWriter(memoryStream))
			{
				Write(bw);
			}
			return memoryStream.ToArray();
		}
	}
	public abstract class LevelSessionBehaviour : MonoBehaviour
	{
		protected bool started;

		protected bool stopped;

		private void Update()
		{
			if (stopped)
			{
				return;
			}
			if (!started)
			{
				if (!(MonoSingleton<StatsManager>.Instance.seconds > 0f))
				{
					return;
				}
				StartSession();
			}
			if (started && MonoSingleton<StatsManager>.Instance.infoSent)
			{
				StopSession();
			}
			OnSessionUpdate();
		}

		protected abstract void OnSessionUpdate();

		private void StartSession()
		{
			started = true;
			OnStartSession();
		}

		protected abstract void OnStartSession();

		protected abstract void OnStopSession();

		private void StopSession()
		{
			stopped = true;
			OnStopSession();
		}
	}
	public class RunEditor : MonoBehaviour
	{
		[SerializeField]
		private RunManagerMenu runManager;

		[SerializeField]
		private Text runFileName;

		[SerializeField]
		private Text levelText;

		[SerializeField]
		private Text runnerNameText;

		[SerializeField]
		private Text dateCreatedText;

		[SerializeField]
		private Text goalKillsText;

		[SerializeField]
		private Text goalStyleText;

		[SerializeField]
		private Text goalTimeText;

		[SerializeField]
		private Text goalDeathsText;

		[SerializeField]
		private GameObject flagsContainer;

		[SerializeField]
		private GameObject cheatsBubble;

		[SerializeField]
		private GameObject majorAssistsBubble;

		[SerializeField]
		private GameObject noDamageBubble;

		[SerializeField]
		private Button openInFolderButton;

		[SerializeField]
		private Button backButton;

		[SerializeField]
		private Button saveButton;

		[SerializeField]
		private Button deleteButton;

		[SerializeField]
		private Button setCustomGoalButton;

		[SerializeField]
		private InputField titleField;

		[SerializeField]
		private InputField descriptionField;

		[SerializeField]
		private Text finalRankText;

		[SerializeField]
		private Image finalRankImage;

		public Button BackButton => backButton;

		public void SetRecording(SessionRecordingMetadata metadata)
		{
			//IL_0030: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Expected O, but got Unknown
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0398: Expected O, but got Unknown
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Expected O, but got Unknown
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Expected O, but got Unknown
			bool isValid = SteamClient.IsValid;
			bool flag = false;
			if (isValid)
			{
				flag = metadata.SteamID == SteamId.op_Implicit(SteamClient.SteamId);
			}
			bool flag2 = metadata.LevelName == SceneHelper.CurrentScene;
			runFileName.text = "-- " + Path.GetFileNameWithoutExtension(metadata.LocatedFilePath) + " --";
			levelText.text = metadata.LevelName;
			if (SteamClient.IsValid)
			{
				Text obj = runnerNameText;
				Friend val = new Friend(SteamId.op_Implicit(metadata.SteamID));
				obj.text = ((Friend)(ref val)).Name;
			}
			else
			{
				runnerNameText.text = "Player (" + metadata.SteamID.ToString().Substring(0, 5) + "...)";
			}
			dateCreatedText.text = metadata.DateCreated.ToString("MM/dd/yyyy hh:mm:ss");
			goalKillsText.text = metadata.StatGoal.Kills.ToString("000");
			goalStyleText.text = metadata.StatGoal.Style.ToString("000");
			goalTimeText.text = metadata.GetTimeString();
			goalDeathsText.text = metadata.StatGoal.Deaths.ToString("000");
			titleField.SetTextWithoutNotify(metadata.Title);
			((UnityEventBase)titleField.onEndEdit).RemoveAllListeners();
			((Selectable)titleField).interactable = flag;
			string title = metadata.Title;
			descriptionField.SetTextWithoutNotify(metadata.Description);
			((UnityEventBase)descriptionField.onEndEdit).RemoveAllListeners();
			((Selectable)descriptionField).interactable = flag;
			string desc = metadata.Description;
			if (flag)
			{
				((UnityEvent<string>)(object)descriptionField.onEndEdit).AddListener((UnityAction<string>)delegate(string text)
				{
					desc = text;
					((Component)saveButton).gameObject.SetActive(desc != metadata.Description || title != metadata.Title);
				});
				((UnityEvent<string>)(object)titleField.onEndEdit).AddListener((UnityAction<string>)delegate(string text)
				{
					title = text;
					((Component)saveButton).gameObject.SetActive(desc != metadata.Description || title != metadata.Title);
				});
			}
			bool active = metadata.CheatsUsed || metadata.MajorAssistsUsed || metadata.NoDamage;
			flagsContainer.SetActive(active);
			cheatsBubble.SetActive(metadata.CheatsUsed);
			majorAssistsBubble.SetActive(metadata.MajorAssistsUsed);
			noDamageBubble.SetActive(metadata.NoDamage);
			((UnityEventBase)openInFolderButton.onClick).RemoveAllListeners();
			((UnityEvent)openInFolderButton.onClick).AddListener((UnityAction)delegate
			{
				Application.OpenURL(Path.GetDirectoryName(metadata.LocatedFilePath));
			});
			((UnityEventBase)saveButton.onClick).RemoveAllListeners();
			((Component)saveButton).gameObject.SetActive(false);
			if (flag)
			{
				((UnityEvent)saveButton.onClick).AddListener((UnityAction)delegate
				{
					metadata.Title = title;
					metadata.Description = desc;
					GhostFileManager.UpdateMetadata(metadata);
					((Component)saveButton).gameObject.SetActive(false);
					runManager.RebuildMenu();
				});
			}
			((UnityEventBase)deleteButton.onClick).RemoveAllListeners();
			((UnityEvent)deleteButton.onClick).AddListener((UnityAction)delegate
			{
				ModalDialogue.ShowSimple("WARNING", "You are about to permanently delete this run. Confirm?", (Action<bool>)delegate(bool r)
				{
					if (r)
					{
						GhostFileManager.DeleteRun(metadata);
						runManager.RebuildMenu();
						((Component)this).gameObject.SetActive(false);
						runManager.Open();
					}
				}, "Delete", "Cancel");
			});
			((UnityEventBase)setCustomGoalButton.onClick).RemoveAllListeners();
			((Component)setCustomGoalButton).gameObject.SetActive(flag2);
			if (flag2)
			{
				((UnityEvent)setCustomGoalButton.onClick).AddListener((UnityAction)delegate
				{
					TrackerManager.SetCustomGoal(metadata.StatGoal);
					((UnityEventBase)setCustomGoalButton.onClick).RemoveAllListeners();
				});
			}
		}
	}
	public class RunList : MonoBehaviour
	{
		[SerializeField]
		private GameObject listElementPrefab;

		[SerializeField]
		private RectTransform contentBody;

		[SerializeField]
		private Button selectAllButton;

		[SerializeField]
		private Button deselectAllButton;

		[SerializeField]
		private Button backButton;

		[SerializeField]
		private Text levelNameText;

		private List<GameObject> instancedElements;

		private bool isInLevelOfFolder;

		public void SetName(string name)
		{
			isInLevelOfFolder = name == SceneHelper.CurrentScene;
			levelNameText.text = name;
		}

		private void ClearList()
		{
			if (instancedElements != null)
			{
				for (int i = 0; i < instancedElements.Count; i++)
				{
					if (!((Object)(object)instancedElements[i] == (Object)null))
					{
						GameObject val = instancedElements[i];
						instancedElements[i] = null;
						Object.Destroy((Object)(object)val);
					}
				}
				instancedElements.Clear();
			}
			else
			{
				instancedElements = new List<GameObject>();
			}
		}

		public void SetList(List<SessionRecordingMetadata> metadatas, Action<SessionRecordingMetadata> onRunSelected)
		{
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Expected O, but got Unknown
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Expected O, but got Unknown
			ClearList();
			foreach (SessionRecordingMetadata metadata in metadatas.OrderByDescending((SessionRecordingMetadata x) => x.DateCreated.Ticks))
			{
				GameObject val = Object.Instantiate<GameObject>(listElementPrefab, (Transform)(object)contentBody);
				Button componentInChildren = val.GetComponentInChildren<Button>();
				Text componentInChildren2 = val.GetComponentInChildren<Text>();
				Toggle componentInChildren3 = val.GetComponentInChildren<Toggle>();
				instancedElements.Add(val);
				string text = "Player (" + metadata.SteamID.ToString().Substring(0, 5) + "...)";
				if (SteamClient.IsValid)
				{
					Friend val2 = new Friend(SteamId.op_Implicit(metadata.SteamID));
					text = ((Friend)(ref val2)).Name;
				}
				componentInChildren2.text = text + " // " + metadata.Title + " // " + Path.GetFileNameWithoutExtension(metadata.LocatedFilePath);
				((UnityEvent)componentInChildren.onClick).AddListener((UnityAction)delegate
				{
					onRunSelected(metadata);
				});
				componentInChildren3.SetIsOnWithoutNotify(GhostManager.IsGhostEnabled(metadata.LocatedFilePath));
				((Component)componentInChildren3).gameObject.SetActive(isInLevelOfFolder);
				((UnityEvent<bool>)(object)componentInChildren3.onValueChanged).AddListener((UnityAction<bool>)delegate(bool value)
				{
					GhostManager.SetGhostEnabled(metadata.LocatedFilePath, value);
				});
			}
			((UnityEvent)selectAllButton.onClick).AddListener((UnityAction)delegate
			{
				foreach (GameObject instancedElement in instancedElements)
				{
					Toggle componentInChildren5 = instancedElement.GetComponentInChildren<Toggle>();
					componentInChildren5.isOn = true;
				}
			});
			((UnityEvent)deselectAllButton.onClick).AddListener((UnityAction)delegate
			{
				foreach (GameObject instancedElement2 in instancedElements)
				{
					Toggle componentInChildren4 = instancedElement2.GetComponentInChildren<Toggle>();
					componentInChildren4.isOn = false;
				}
			});
		}

		public void SetBackAction(Action onBackPressed)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			((UnityEventBase)backButton.onClick).RemoveAllListeners();
			((UnityEvent)backButton.onClick).AddListener((UnityAction)delegate
			{
				onBackPressed?.Invoke();
			});
		}
	}
	public class RunManagerMenu : MonoBehaviour
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__13_0;

			public static Func<SessionRecordingMetadata, string> <>9__15_0;

			public static Func<string, string> <>9__15_1;

			public static Func<string, string> <>9__15_2;

			public static Func<KeyValuePair<string, List<SessionRecordingMetadata>>, bool> <>9__15_4;

			public static Func<KeyValuePair<string, List<SessionRecordingMetadata>>, string> <>9__15_5;

			public static Func<KeyValuePair<string, List<SessionRecordingMetadata>>, List<SessionRecordingMetadata>> <>9__15_6;

			public static Action <>9__21_0;

			public static Action <>9__21_1;

			public static Action <>9__21_2;

			internal void <Awake>b__13_0()
			{
				Application.OpenURL("https://discord.gg/kCHnwMDPt4");
			}

			internal string <RebuildMenu>b__15_0(SessionRecordingMetadata x)
			{
				return x.LevelName;
			}

			internal string <RebuildMenu>b__15_1(string x)
			{
				return x;
			}

			internal string <RebuildMenu>b__15_2(string x)
			{
				return x;
			}

			internal bool <RebuildMenu>b__15_4(KeyValuePair<string, List<SessionRecordingMetadata>> x)
			{
				return x.Key == SceneHelper.CurrentScene;
			}

			internal string <RebuildMenu>b__15_5(KeyValuePair<string, List<SessionRecordingMetadata>> x)
			{
				return x.Key;
			}

			internal List<SessionRecordingMetadata> <RebuildMenu>b__15_6(KeyValuePair<string, List<SessionRecordingMetadata>> x)
			{
				return x.Value;
			}

			internal void <NotifyUpdateAvailable>b__21_0()
			{
				Application.OpenURL("https://www.github.com/Hydraxous/EasyPZ-ULTRAKILL/releases/latest");
			}

			internal void <NotifyUpdateAvailable>b__21_1()
			{
			}

			internal void <NotifyUpdateAvailable>b__21_2()
			{
				((ConfigValueElement<bool>)(object)notifyOnUpdateAvailable).SetValue(false);
			}
		}

		[SerializeField]
		private GameObject container;

		[SerializeField]
		private RunEditor runEditor;

		[SerializeField]
		private RectTransform listRoot;

		[SerializeField]
		private Button discordButton;

		[SerializeField]
		private Button backButton;

		[SerializeField]
		private RectTransform folderButtonContentBody;

		[SerializeField]
		private RectTransform foldersRoot;

		[SerializeField]
		private GameObject folderListPrefab;

		private List<GameObject> instancedMenus;

		private List<GameObject> instancedFolderButtons;

		private static RunManagerMenu instance;

		[Configgable("Extras/Advanced", "Notify on update available", 0, null)]
		private static ConfigToggle notifyOnUpdateAvailable = new ConfigToggle(true);

		private static bool openedOnce;

		private void Awake()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_0026: 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: Expected O, but got Unknown
			instance = this;
			ButtonClickedEvent onClick = discordButton.onClick;
			object obj = <>c.<>9__13_0;
			if (obj == null)
			{
				UnityAction val = delegate
				{
					Application.OpenURL("https://discord.gg/kCHnwMDPt4");
				};
				<>c.<>9__13_0 = val;
				obj = (object)val;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
			((UnityEvent)backButton.onClick).AddListener((UnityAction)delegate
			{
				Close();
			});
			RebuildMenu();
			container.SetActive(false);
			((Component)listRoot).gameObject.SetActive(false);
			((Component)foldersRoot).gameObject.SetActive(false);
			((Component)runEditor).gameObject.SetActive(false);
		}

		[Configgable("Ghosts", "Manage Runs", 0, null)]
		private static void OpenMenuStatic()
		{
			if ((Object)(object)instance == (Object)null)
			{
				Debug.LogError((object)"RunManagerMenu could not be found.");
				return;
			}
			ConfigurationMenu.Close();
			instance.Open();
		}

		public void RebuildMenu()
		{
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Expected O, but got Unknown
			ClearMenus();
			List<SessionRecordingMetadata> metadatas = GhostFileManager.FetchMetadata();
			List<string> source = (from x in metadatas.Select((SessionRecordingMetadata x) => x.LevelName).Distinct()
				orderby x
				select x).ToList();
			Dictionary<string, List<SessionRecordingMetadata>> source2 = source.ToDictionary((string x) => x, (string x) => metadatas.Where((SessionRecordingMetadata y) => y.LevelName == x).ToList());
			source2 = source2.OrderByDescending((KeyValuePair<string, List<SessionRecordingMetadata>> x) => x.Key == SceneHelper.CurrentScene).ToDictionary((KeyValuePair<string, List<SessionRecordingMetadata>> x) => x.Key, (KeyValuePair<string, List<SessionRecordingMetadata>> x) => x.Value);
			foreach (KeyValuePair<string, List<SessionRecordingMetadata>> item in source2)
			{
				GameObject folder = Object.Instantiate<GameObject>(folderListPrefab, (Transform)(object)foldersRoot);
				RunList list = folder.GetComponent<RunList>();
				bool flag = item.Key == SceneHelper.CurrentScene;
				list.SetName(item.Key);
				UnityAction val = default(UnityAction);
				list.SetList(item.Value, delegate(SessionRecordingMetadata d)
				{
					//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_0054: Expected O, but got Unknown
					//IL_0059: Expected O, but got Unknown
					((UnityEventBase)runEditor.BackButton.onClick).RemoveAllListeners();
					ButtonClickedEvent onClick = runEditor.BackButton.onClick;
					UnityAction obj = val;
					if (obj == null)
					{
						UnityAction val3 = delegate
						{
							((Component)runEditor).gameObject.SetActive(false);
							((Component)foldersRoot).gameObject.SetActive(true);
							if ((Object)(object)folder != (Object)null)
							{
								folder.SetActive(true);
							}
							else
							{
								((Component)foldersRoot).gameObject.SetActive(false);
								((Component)listRoot).gameObject.SetActive(true);
							}
						};
						UnityAction val4 = val3;
						val = val3;
						obj = val4;
					}
					((UnityEvent)onClick).AddListener(obj);
					OpenRunInEditor(d);
				});
				folder.SetActive(false);
				GameObject val2 = Object.Instantiate<GameObject>(PluginAssets.ButtonPrefab, (Transform)(object)folderButtonContentBody);
				instancedFolderButtons.Add(val2);
				Button component = val2.GetComponent<Button>();
				Text componentInChildren = val2.GetComponentInChildren<Text>();
				RectTransform component2 = val2.GetComponent<RectTransform>();
				component2.sizeDelta = new Vector2(component2.sizeDelta.x, 35f);
				componentInChildren.text = $"{item.Key} ({item.Value.Count})";
				if (flag)
				{
					componentInChildren.text = "<color=orange>" + componentInChildren.text + "</color>";
				}
				instancedMenus.Add(folder);
				((UnityEvent)component.onClick).AddListener((UnityAction)delegate
				{
					OpenFolder(list);
				});
			}
		}

		private void Update()
		{
			if (container.activeInHierarchy && Input.GetKeyDown((KeyCode)27))
			{
				if (((Component)runEditor).gameObject.activeInHierarchy)
				{
					((Component)runEditor).gameObject.SetActive(false);
					((Component)foldersRoot).gameObject.SetActive(true);
				}
				else if (((Component)foldersRoot).gameObject.activeInHierarchy)
				{
					((Component)foldersRoot).gameObject.SetActive(false);
					((Component)listRoot).gameObject.SetActive(true);
				}
				else if (container.activeInHierarchy)
				{
					Close();
				}
			}
		}

		private void OpenRunInEditor(SessionRecordingMetadata metadata)
		{
			runEditor.SetRecording(metadata);
			((Component)runEditor).gameObject.SetActive(true);
			((Component)listRoot).gameObject.SetActive(false);
			((Component)foldersRoot).gameObject.SetActive(false);
		}

		private void OpenFolder(RunList list)
		{
			list.SetBackAction(delegate
			{
				((Component)listRoot).gameObject.SetActive(true);
				((Component)foldersRoot).gameObject.SetActive(false);
				((Component)list).gameObject.SetActive(false);
			});
			((Component)foldersRoot).gameObject.SetActive(true);
			((Component)listRoot).gameObject.SetActive(false);
			((Component)list).gameObject.SetActive(true);
		}

		private void ClearMenus()
		{
			if (instancedMenus != null)
			{
				for (int i = 0; i < instancedMenus.Count; i++)
				{
					if (!((Object)(object)instancedMenus[i] == (Object)null))
					{
						GameObject va