Decompiled source of CybergrindMusicExplorer v1.6.3

plugins/CybergrindMusicExplorer/CybergrindMusicExplorer.dll

Decompiled 7 months ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using BepInEx;
using CybergrindMusicExplorer.Components;
using CybergrindMusicExplorer.Data;
using CybergrindMusicExplorer.Downloader;
using CybergrindMusicExplorer.Downloader.Data.Soundcloud;
using CybergrindMusicExplorer.Downloader.Data.Youtube;
using CybergrindMusicExplorer.GUI;
using CybergrindMusicExplorer.GUI.Attributes;
using CybergrindMusicExplorer.GUI.Controllers;
using CybergrindMusicExplorer.GUI.Elements;
using CybergrindMusicExplorer.Patches;
using CybergrindMusicExplorer.Scripts;
using CybergrindMusicExplorer.Scripts.Data;
using CybergrindMusicExplorer.Scripts.UI;
using CybergrindMusicExplorer.Scripts.Utils;
using CybergrindMusicExplorer.Util;
using CybergrindMusicExplorer.Util.Patching;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Microsoft.Win32.SafeHandles;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SubtitlesParser.Classes;
using SubtitlesParser.Classes.Parsers;
using TMPro;
using TagLib;
using TagLib.Aac;
using TagLib.Aiff;
using TagLib.Ape;
using TagLib.Asf;
using TagLib.Audible;
using TagLib.Dsf;
using TagLib.Flac;
using TagLib.Gif;
using TagLib.IFD;
using TagLib.IFD.Entries;
using TagLib.IFD.Makernotes;
using TagLib.IFD.Tags;
using TagLib.IIM;
using TagLib.Id3v1;
using TagLib.Id3v2;
using TagLib.Image;
using TagLib.Image.NoMetadata;
using TagLib.Jpeg;
using TagLib.Matroska;
using TagLib.Mpeg;
using TagLib.Mpeg4;
using TagLib.MusePack;
using TagLib.NonContainer;
using TagLib.Ogg;
using TagLib.Ogg.Codecs;
using TagLib.Png;
using TagLib.Riff;
using TagLib.Tiff;
using TagLib.Tiff.Arw;
using TagLib.Tiff.Cr2;
using TagLib.Tiff.Dng;
using TagLib.Tiff.Nef;
using TagLib.Tiff.Pef;
using TagLib.Tiff.Rw2;
using TagLib.WavPack;
using TagLib.Xmp;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Xabe.FFmpeg;
using Xabe.FFmpeg.Events;
using Xabe.FFmpeg.Exceptions;
using Xabe.FFmpeg.Streams;
using Xabe.FFmpeg.Streams.SubtitleStream;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CybergrindMusicExplorer")]
[assembly: AssemblyDescription("Customised music player for Cyber Grind")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CybergrindMusicExplorer")]
[assembly: AssemblyCopyright("Copyright © 2024 Flazhik")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("D79551C3-9E3E-46FF-95A5-029A9093600A")]
[assembly: AssemblyFileVersion("1.6.3.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.6.3.0")]
namespace CybergrindMusicExplorer
{
	public class AssetsManager : MonoSingleton<AssetsManager>
	{
		private const BindingFlags Flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static Dictionary<string, Object> _prefabs = new Dictionary<string, Object>();

		private AssetBundle bundle;

		public void LoadAssets()
		{
			bundle = AssetBundle.LoadFromMemory(Resources.CybergrindMusicExplorer);
		}

		public void RegisterPrefabs()
		{
			string[] array = bundle.AllAssetNames();
			foreach (string text in array)
			{
				_prefabs.Add(text, bundle.LoadAsset<Object>(text));
			}
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			for (int i = 0; i < types.Length; i++)
			{
				CheckType(types[i]);
			}
		}

		private static void CheckType(IReflect type)
		{
			type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).ToList().ForEach(ProcessField);
		}

		private static void ProcessField(FieldInfo field)
		{
			if (!field.FieldType.IsArray && field.FieldType.IsAssignableFrom(typeof(GameObject)) && field.IsStatic)
			{
				PrefabAsset customAttribute = field.GetCustomAttribute<PrefabAsset>();
				if (customAttribute != null)
				{
					field.SetValue(null, _prefabs[customAttribute.Path]);
				}
			}
		}

		public static Object GetAsset(string assetName)
		{
			return _prefabs[assetName];
		}
	}
	[BepInProcess("ULTRAKILL.exe")]
	[BepInPlugin("dev.flazhik.cybergrindexplorer", "CybergrindMusicExplorer", "1.6.3")]
	public class CybergrindMusicExplorer : BaseUnityPlugin
	{
		private static System.Version _newestVersion = new System.Version("1.0.0");

		private static CustomMusicPlaylistEditor _editor;

		private EnhancedMusicFileBrowser fileBrowser;

		private GameObject cybergrindMusicExplorerSettings;

		private GUIManager GUIManager;

		private CybergrindEffectsChanger cybergrindEffectsChanger;

		private TracksDownloadManager tracksDownloadManager;

		private bool menuMessageIsShown;

		public static CustomMusicPlaylistEditor GetPlaylistEditor()
		{
			return _editor;
		}

		public static System.Version GetNewestVersion()
		{
			return _newestVersion;
		}

		private void Awake()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Initializing Cybergrind Music Explorer");
			Startup();
			MonoSingleton<AssetsManager>.Instance.LoadAssets();
			MonoSingleton<AssetsManager>.Instance.RegisterPrefabs();
		}

		private void Startup()
		{
			SceneManager.sceneLoaded += OnSceneLoaded;
			GUIManager.Init();
			cybergrindEffectsChanger = MonoSingleton<CybergrindEffectsChanger>.Instance;
			tracksDownloadManager = MonoSingleton<TracksDownloadManager>.Instance;
			RetrieveNewestVersion();
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (scene != SceneManager.GetActiveScene())
			{
				return;
			}
			string currentScene = SceneHelper.CurrentScene;
			if (!(currentScene == "Endless"))
			{
				if (currentScene == "Main Menu")
				{
					global::CybergrindMusicExplorer.Patches.Patches.PatchOnStartOptionsMenu();
					global::CybergrindMusicExplorer.Patches.Patches.PatchOnEnableOptionsMenu();
				}
				return;
			}
			MonoSingleton<CybergrindMusicExplorerManager>.Instance.allowMusicBoost = false;
			global::CybergrindMusicExplorer.Patches.Patches.PatchMusicManager();
			global::CybergrindMusicExplorer.Patches.Patches.PatchMusicChanger();
			if (!((Object)(object)fileBrowser != (Object)null))
			{
				OnCybergrind();
			}
		}

		private void OnCybergrind()
		{
			MonoSingleton<CybergrindMusicExplorerManager>.Instance.allowMusicBoost = true;
			MonoSingleton<CalmThemeManager>.Instance.Init();
			global::CybergrindMusicExplorer.Patches.Patches.PatchAudioMixer();
			global::CybergrindMusicExplorer.Patches.Patches.PatchPlaylist();
			global::CybergrindMusicExplorer.Patches.Patches.PatchCustomMusicPlaylistEditor();
			global::CybergrindMusicExplorer.Patches.Patches.PatchDirectoryTree();
			global::CybergrindMusicExplorer.Patches.Patches.PatchFinalCyberRank();
			global::CybergrindMusicExplorer.Patches.Patches.PatchWaveMenu();
			global::CybergrindMusicExplorer.Patches.Patches.PatchScreenZone();
			EnhancedMusicFileBrowser.OnInit += OnEnhancedBrowserInit;
			CustomMusicFileBrowser obj = Object.FindObjectOfType<CustomMusicFileBrowser>();
			GameObject gameObject = ((Component)((Component)obj).transform).gameObject;
			fileBrowser = gameObject.AddComponent<EnhancedMusicFileBrowser>();
			Object.Destroy((Object)(object)obj);
			ClearTmpDirectory();
		}

		private void OnEnhancedBrowserInit()
		{
			_editor = Object.FindObjectOfType<CustomMusicPlaylistEditor>();
			global::CybergrindMusicExplorer.Patches.Patches.PatchMusicPlayer();
		}

		private static void ClearTmpDirectory()
		{
			if (!PathsUtils.TemporaryFilesDirectory.Exists)
			{
				return;
			}
			FileInfo[] files = PathsUtils.TemporaryFilesDirectory.GetFiles();
			foreach (FileInfo fileInfo in files)
			{
				try
				{
					fileInfo.Delete();
				}
				catch (Exception)
				{
					Debug.LogWarning((object)("Can't delete temporary file " + fileInfo.Name));
				}
			}
		}

		private static async Task RetrieveNewestVersion()
		{
			await UpdatesManager.GetNewVersion();
			_newestVersion = UpdatesManager.NewestVersion;
		}
	}
	public class CybergrindMusicExplorerManager : MonoSingleton<CybergrindMusicExplorerManager>
	{
		private readonly PrefsManager prefsManager = MonoSingleton<PrefsManager>.Instance;

		public bool allowMusicBoost;

		public bool ShowCurrentTrackPanelIndefinitely
		{
			get
			{
				return prefsManager.GetBoolLocal("cyberGrind.musicExplorer.showCurrentTrackPanelIndefinitely", false);
			}
			set
			{
				prefsManager.SetBoolLocal("cyberGrind.musicExplorer.showCurrentTrackPanelIndefinitely", value);
			}
		}

		public float CustomTracksBoost
		{
			get
			{
				return prefsManager.GetFloatLocal("cyberGrind.musicExplorer.customTracksVolumeBoost", 0f);
			}
			set
			{
				prefsManager.SetFloatLocal("cyberGrind.musicExplorer.customTracksVolumeBoost", value);
			}
		}

		public float MenuUpscale
		{
			get
			{
				return prefsManager.GetFloatLocal("cyberGrind.musicExplorer.menuUpscale", 0f);
			}
			set
			{
				prefsManager.SetFloatLocal("cyberGrind.musicExplorer.menuUpscale", value);
			}
		}

		public bool PlayCalmTheme
		{
			get
			{
				return prefsManager.GetBoolLocal("cyberGrind.musicExplorer.playCalmTheme", true);
			}
			set
			{
				prefsManager.SetBoolLocal("cyberGrind.musicExplorer.playCalmTheme", value);
			}
		}

		public bool PreventDuplicateTracks
		{
			get
			{
				return prefsManager.GetBoolLocal("cyberGrind.musicExplorer.preventDuplicateTracks", false);
			}
			set
			{
				prefsManager.SetBoolLocal("cyberGrind.musicExplorer.preventDuplicateTracks", value);
			}
		}

		public bool AddDownloadedTracks
		{
			get
			{
				return prefsManager.GetBoolLocal("cyberGrind.musicExplorer.addDownloadedTracks", false);
			}
			set
			{
				prefsManager.SetBoolLocal("cyberGrind.musicExplorer.addDownloadedTracks", value);
			}
		}

		public bool EnableTracksPreview
		{
			get
			{
				return prefsManager.GetBoolLocal("cyberGrind.musicExplorer.enableTracksPreview", true);
			}
			set
			{
				prefsManager.SetBoolLocal("cyberGrind.musicExplorer.enableTracksPreview", value);
			}
		}

		public bool ShowBigNowPlayingPanel
		{
			get
			{
				return prefsManager.GetBoolLocal("cyberGrind.musicExplorer.bigNowPlayingPanel", true);
			}
			set
			{
				prefsManager.SetBoolLocal("cyberGrind.musicExplorer.bigNowPlayingPanel", value);
			}
		}

		public int CalmThemeEnemiesThreshold
		{
			get
			{
				return prefsManager.GetIntLocal("cyberGrind.musicExplorer.calmThemeEnemiesThreshold", 2);
			}
			set
			{
				prefsManager.SetIntLocal("cyberGrind.musicExplorer.calmThemeEnemiesThreshold", value);
			}
		}

		public int SelectedPlaylistSlot
		{
			get
			{
				return prefsManager.GetIntLocal("cyberGrind.musicExplorer.selectedPlaylistSlot", 1);
			}
			set
			{
				prefsManager.SetIntLocal("cyberGrind.musicExplorer.selectedPlaylistSlot", value);
			}
		}

		public int NextTrackBinding => prefsManager.GetIntLocal("cyberGrind.musicExplorer.keyBinding.CGMENextTrack", 284);

		public int MenuBinding => prefsManager.GetIntLocal("cyberGrind.musicExplorer.keyBinding.CGMEMenu", 285);

		public int PlaybackMenuBinding => prefsManager.GetIntLocal("cyberGrind.musicExplorer.keyBinding.CGMEPlaybackMenu", 96);

		public int DisablePlayerBinding => prefsManager.GetIntLocal("cyberGrind.musicExplorer.keyBinding.CGMEDisablePlayer", 291);

		public void SetIntLocal(string key, int content)
		{
			prefsManager.SetIntLocal(key, content);
		}
	}
	internal static class PluginInfo
	{
		public const string GUID = "dev.flazhik.cybergrindexplorer";

		public const string NAME = "CybergrindMusicExplorer";

		public const string VERSION = "1.6.3";
	}
	[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
	[DebuggerNonUserCode]
	[CompilerGenerated]
	internal class Resources
	{
		private static ResourceManager resourceMan;

		private static CultureInfo resourceCulture;

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

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

		internal static byte[] CybergrindMusicExplorer => (byte[])ResourceManager.GetObject("CybergrindMusicExplorer", resourceCulture);

		internal Resources()
		{
		}
	}
}
namespace CybergrindMusicExplorer.Util
{
	public static class CustomTracksNamingUtil
	{
		public static readonly Dictionary<string, AudioType> AudioTypesByExtension = new Dictionary<string, AudioType>
		{
			{
				".mp3",
				(AudioType)13
			},
			{
				".wav",
				(AudioType)20
			},
			{
				".ogg",
				(AudioType)14
			}
		};

		private static readonly List<string> IntroLoopPostfixes = new List<string> { "intro", "loop" };

		private static readonly List<string> SpecialPostfixes = new List<string> { "intro", "loop", "calm", "calmloop", "calmintro" };

		public static FileInfo FileWithAnotherExtension(FileInfo path, string extension)
		{
			return new FileInfo(Path.GetDirectoryName(path.FullName) + "\\" + Path.GetFileNameWithoutExtension(path.FullName) + "." + extension);
		}

		public static FileInfo WithPostfix(FileInfo path, string postfix)
		{
			return new FileInfo(Path.GetDirectoryName(path.FullName) + "\\" + Path.GetFileNameWithoutExtension(path.FullName) + "_" + postfix + path.Extension);
		}

		public static FileInfo WithoutPostfix(FileInfo path)
		{
			if (HasSpecialPostfix(path))
			{
				return new FileInfo(Regex.Replace(path.FullName, "_[a-zA-Z]+\\.[a-zA-Z0-9]+$", path.Extension));
			}
			return path;
		}

		public static bool HasSpecialPostfix(FileInfo path)
		{
			return SpecialPostfixes.Any((string postfix) => HasSpecialPostfix(path, postfix));
		}

		public static bool IntroOrLoopPart(FileInfo path)
		{
			return IntroLoopPostfixes.Any((string postfix) => HasSpecialPostfix(path, postfix));
		}

		public static bool HasIntroAndLoop(IGrouping<string, FileInfo> tracks)
		{
			return IntroLoopPostfixes.All((string postfix) => tracks.Any((FileInfo track) => HasSpecialPostfix(track, postfix)));
		}

		public static bool HasSpecialPostfix(FileInfo path, string postfix)
		{
			return Path.GetFileNameWithoutExtension(path.Name).EndsWith("_" + postfix);
		}
	}
	public class DeckShuffled<T> : IEnumerable<T>, IEnumerable
	{
		private List<T> current;

		public DeckShuffled(IEnumerable<T> target)
		{
			current = Randomize(target).ToList();
		}

		public void Reshuffle()
		{
			if (current.Count > 1)
			{
				IEnumerable<T> source = current.Take(Mathf.FloorToInt((float)(current.Count / 2)));
				IEnumerable<T> source2 = current.Skip(Mathf.FloorToInt((float)(current.Count / 2)));
				current = Randomize(source).Concat(Randomize(source2)).ToList();
			}
		}

		private static IEnumerable<T> Randomize(IEnumerable<T> source)
		{
			T[] arr = source.ToArray();
			int i = arr.Length - 1;
			while (i > 0)
			{
				int swapIndex = Random.Range(0, i + 1);
				yield return arr[swapIndex];
				arr[swapIndex] = arr[i];
				int num = i - 1;
				i = num;
			}
			yield return arr[0];
		}

		public IEnumerator<T> GetEnumerator()
		{
			return current.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return current.GetEnumerator();
		}
	}
	public static class HttpUtils
	{
		private const int RetryAttempts = 3;

		private static readonly HttpClient Client;

		static HttpUtils()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			Client = new HttpClient();
			Client.Timeout = TimeSpan.FromSeconds(5.0);
			Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
			Client.DefaultRequestHeaders.UserAgent.TryParseAdd("com.google.android.youtube/17.36.4 (Linux; U; Android 12; GB) gzip");
		}

		public static IEnumerator GetRequest<TRsp>(string url, Action<TRsp> callback)
		{
			return Request(ReadResponse<TRsp>(() => Client.GetAsync(url)), callback);
		}

		public static IEnumerator PostRequest<TReq, TRsp>(string url, TReq request, Action<TRsp> callback)
		{
			return Request(ReadResponse<TRsp>(() => Client.PostAsync(url, (HttpContent)new StringContent(JsonConvert.SerializeObject((object)request), Encoding.UTF8))), callback);
		}

		private static IEnumerator Request<TRsp>(Task<TRsp> task, Action<TRsp> callback)
		{
			yield return (object)new WaitUntil((Func<bool>)(() => task.IsCompleted || task.IsCanceled || task.IsFaulted));
			if (!task.IsCompleted || task.Exception != null)
			{
				if (task.Exception != null)
				{
					Debug.LogWarning((object)("HTTP error has occurred: " + task.Exception.Message));
				}
				yield break;
			}
			try
			{
				callback(task.Result);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("HTTP error has occurred: " + ex.Message));
			}
		}

		private static async Task<TRsp> ReadResponse<TRsp>(Func<Task<HttpResponseMessage>> task)
		{
			TRsp response = default(TRsp);
			for (int i = 0; i < 3; i++)
			{
				string text;
				try
				{
					text = await (await task()).Content.ReadAsStringAsync();
					if (text == null)
					{
						continue;
					}
				}
				catch (Exception)
				{
					continue;
				}
				response = JsonConvert.DeserializeObject<TRsp>(text);
				if (response != null)
				{
					break;
				}
			}
			return response;
		}

		public static IEnumerator DownloadFile(WebClient webClient, string url, string dst, Action<bool> success)
		{
			bool downloading = true;
			using (webClient)
			{
				try
				{
					webClient.Proxy = null;
					webClient.DownloadFileCompleted += delegate(object sender, AsyncCompletedEventArgs e)
					{
						if (e.Error != null || e.Cancelled)
						{
							success(obj: false);
						}
						else
						{
							success(obj: true);
						}
						downloading = false;
					};
					webClient.DownloadFileAsync(new Uri(url), dst);
				}
				catch (Exception)
				{
					success(obj: false);
					downloading = false;
					yield break;
				}
				yield return (object)new WaitUntil((Func<bool>)(() => !downloading));
			}
		}

		public static IEnumerator LoadTexture(string url, Action<Texture> callback)
		{
			UnityWebRequest request = UnityWebRequestTexture.GetTexture(url);
			try
			{
				request.SendWebRequest();
				yield return (object)new WaitUntil((Func<bool>)(() => request.isDone || request.error != null));
				if (request.error != null)
				{
					Debug.LogError((object)("An error has occured while downloading image " + url + ": " + request.error));
				}
				else
				{
					callback((Texture)(object)DownloadHandlerTexture.GetContent(request));
				}
			}
			finally
			{
				if (request != null)
				{
					((IDisposable)request).Dispose();
				}
			}
		}
	}
	public static class JsonUtils
	{
		public static JToken GetOrNull(this JToken obj, string key)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			if (obj[(object)key] == null || (int)obj[(object)key].Type == 10 || (int)obj[(object)key].Type == 11)
			{
				return null;
			}
			return obj[(object)key];
		}

		public static JArray ArrayOrNull(this JToken obj, string key)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			if (obj[(object)key] == null || (int)obj[(object)key].Type != 2)
			{
				return null;
			}
			return (JArray)obj[(object)key];
		}
	}
	public static class KeyUtils
	{
		public static string ToHumanReadable(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Invalid comparison between Unknown and I4
			//IL_0040: 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_006d: Expected I4, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected I4, but got Unknown
			if ((int)key >= 97 && (int)key <= 122)
			{
				return ((char)(65 + (key - 97))).ToString();
			}
			if ((int)key >= 48 && (int)key <= 57)
			{
				return ((char)(48 + (key - 48))).ToString();
			}
			if ((int)key <= 47)
			{
				if ((int)key == 32)
				{
					return " ";
				}
				switch (key - 39)
				{
				case 0:
					return "\"";
				case 6:
					return "-";
				case 5:
					return ",";
				case 7:
					return ".";
				case 8:
					return "/";
				}
			}
			else
			{
				if ((int)key == 59)
				{
					return ";";
				}
				if ((int)key == 61)
				{
					return "=";
				}
				switch (key - 91)
				{
				case 0:
					return "[";
				case 2:
					return "]";
				case 5:
					return "`";
				case 1:
					return "\\";
				}
			}
			return ((object)(KeyCode)(ref key)).ToString();
		}
	}
	public class MetadataUtils
	{
		public static Sprite GetAlbumCoverSprite(TagLib.Tag tags)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_005b: 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)
			if (tags.Pictures.Length == 0)
			{
				return null;
			}
			MemoryStream memoryStream = new MemoryStream(tags.Pictures[0].Data.Data);
			memoryStream.Seek(0L, SeekOrigin.Begin);
			Texture2D val = new Texture2D(2, 2);
			ImageConversion.LoadImage(val, memoryStream.ToArray());
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		}
	}
	public static class PathsUtils
	{
		public static readonly string UltrakillPath = Directory.GetParent(Application.dataPath)?.FullName ?? "C:\\Program Files (x86)\\Steam\\steamapps\\common\\ULTRAKILL";

		private const string FallbackUltrakillPath = "C:\\Program Files (x86)\\Steam\\steamapps\\common\\ULTRAKILL";

		public static readonly string CgmePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		public static readonly string CgmeJsonPath = Path.Combine(UltrakillPath, "Preferences", "CgmePreferences.json");

		public static readonly string CustomSongsPath = Path.Combine(UltrakillPath, "CyberGrind", "Music");

		public static readonly DirectoryInfo SpecialEffectsDirectory = new DirectoryInfo(Path.Combine(CustomSongsPath, "CGME"));

		public static readonly DirectoryInfo TemporaryFilesDirectory = new DirectoryInfo(Path.Combine(CustomSongsPath, "CGME", "Temp"));

		public static string CoerceValidFileName(string filename)
		{
			string text = Regex.Escape(new string(Path.GetInvalidFileNameChars()));
			string pattern = "[" + text + "]+";
			string[] source = new string[25]
			{
				"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4",
				"COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4",
				"LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
			};
			return Enumerable.Aggregate(seed: Regex.Replace(filename, pattern, "_"), source: source.Select((string reservedWord) => "^" + reservedWord + "\\."), func: (string current, string reservedWordPattern) => Regex.Replace(current, reservedWordPattern, "_reservedWord_.", RegexOptions.IgnoreCase));
		}

		public static string RelativePathToDirectory(IDirectoryTree<FileInfo> directory)
		{
			string text = string.Empty;
			IDirectoryTree<FileInfo> val = directory;
			while (val.parent != null)
			{
				text = val.name + "\\" + text;
				val = val.parent;
			}
			return text;
		}
	}
	public class ReflectionUtils
	{
		private static readonly BindingFlags BindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;

		private const BindingFlags BindingFlagsFields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		public static void CloneInstance<TNewType, TOldType>(TOldType oldInstance, TNewType newInstance, List<string> privateFieldsToCopy = null, List<string> fieldsToIgnore = null)
		{
			FieldInfo[] fields = typeof(TOldType).GetFields(BindingFlags);
			FieldInfo[] fields2 = typeof(TNewType).GetFields(BindingFlags);
			privateFieldsToCopy?.ForEach(delegate(string field)
			{
				ClonePrivateBaseField(field, oldInstance, newInstance);
			});
			FieldInfo[] array = fields;
			foreach (FieldInfo field2 in array)
			{
				if (!fields2.Select((FieldInfo f) => f.Name).Any((string n) => n == field2.Name) || field2.IsStatic)
				{
					continue;
				}
				FieldInfo fieldInfo = fields2.FirstOrDefault((FieldInfo f) => f.Name == field2.Name);
				if (fieldsToIgnore == null || !fieldsToIgnore.Contains(fieldInfo.Name))
				{
					fields2.First((FieldInfo f) => f.Name == field2.Name).SetValue(newInstance, field2.GetValue(oldInstance));
				}
			}
		}

		public static object GetPrivate<T>(T instance, Type classType, string field)
		{
			return classType.GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetValue(instance);
		}

		public static void SetPrivate<T, TV>(T instance, Type classType, string field, TV value)
		{
			classType.GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetField).SetValue(instance, value);
		}

		public static void CallPrivate<T>(T instance, Type classType, string method)
		{
			classType.GetMethod(method, BindingFlags.Instance | BindingFlags.NonPublic).Invoke(instance, new object[0]);
		}

		private static void ClonePrivateBaseField<TNewType, TOldType>(string fieldName, TOldType fromObj, TNewType toObj)
		{
			Type type = typeof(TOldType);
			Type type2 = typeof(TNewType);
			bool flag = false;
			do
			{
				FieldInfo fieldInfo = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((FieldInfo f) => f.Name == fieldName);
				FieldInfo fieldInfo2 = type2.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((FieldInfo f) => f.Name == fieldName);
				if (fieldInfo != null && fieldInfo2 != null)
				{
					object value = fieldInfo.GetValue(fromObj);
					fieldInfo2.SetValue(toObj, value);
					flag = true;
				}
				else
				{
					type = type.BaseType;
					type2 = type2.BaseType;
				}
			}
			while (!flag && type != null && type2 != null);
		}

		public static IEnumerable<CodeInstruction> IL(params (OpCode, object)[] instructions)
		{
			return ((IEnumerable<(OpCode, object)>)instructions).Select((Func<(OpCode, object), CodeInstruction>)(((OpCode, object) i) => new CodeInstruction(i.Item1, i.Item2))).ToList();
		}
	}
	public static class StringExtension
	{
		public static string Truncate(this string value, int maxLength)
		{
			if (!string.IsNullOrEmpty(value))
			{
				return value.Substring(0, Math.Min(value.Length, maxLength));
			}
			return value;
		}
	}
	public static class VersionUtils
	{
		public static readonly System.Version ComicallyOldVersion = new System.Version("1.0.0");
	}
}
namespace CybergrindMusicExplorer.Util.Patching
{
	public class PatchRequest
	{
		private const BindingFlags TargetMethodBindingAttributes = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private const BindingFlags HarmonyPatchesAttributes = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;

		private readonly MethodInfo targetMethod;

		private MethodInfo prefix;

		private MethodInfo postfix;

		private MethodInfo transpiler;

		private Harmony harmony;

		private PatchRequest(IReflect targetType, string methodName)
		{
			targetMethod = targetType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		}

		public static PatchRequest PatchMethod(Type targetType, string methodName)
		{
			return new PatchRequest(targetType, methodName);
		}

		public PatchRequest WithPrefix(Type patcherType, string prefixName)
		{
			prefix = patcherType.GetMethod(prefixName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
			return this;
		}

		public PatchRequest WithPostfix(Type patcherType, string postfixName)
		{
			postfix = patcherType.GetMethod(postfixName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
			return this;
		}

		public PatchRequest WithTranspiler(Type patcherType, string postfixName)
		{
			transpiler = patcherType.GetMethod(postfixName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
			return this;
		}

		public PatchRequest Using(Harmony harmonyInstance)
		{
			harmony = harmonyInstance;
			return this;
		}

		public void Once()
		{
			//IL_004e: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			if (harmony == null)
			{
				throw new ArgumentNullException("harmony");
			}
			if (!harmony.GetPatchedMethods().Contains(targetMethod))
			{
				object obj = harmony;
				obj = targetMethod;
				obj = (object)((!(prefix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix));
				obj = (object)((!(postfix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix));
				obj = (object)((!(transpiler != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(transpiler));
				((Harmony)obj).Patch((MethodBase)obj, (HarmonyMethod)obj, (HarmonyMethod)obj, (HarmonyMethod)obj, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}
	}
}
namespace CybergrindMusicExplorer.Scripts
{
	public class LoadingRing : MonoBehaviour
	{
		private void Update()
		{
			((Component)this).transform.Rotate(0f, 0f, -60f * Time.fixedUnscaledDeltaTime);
		}
	}
	public class TracksDownloader : MonoBehaviour
	{
		private const int PageCapacity = 20;

		[SerializeField]
		public GameObject restartButton;

		[SerializeField]
		public GameObject downloadAllButton;

		[SerializeField]
		private GameObject urlField;

		[SerializeField]
		private GameObject loadingRing;

		[SerializeField]
		private GameObject list;

		[SerializeField]
		private GameObject trackEntryPrefab;

		[SerializeField]
		private GameObject paginator;

		[SerializeField]
		private GameObject easterEgg;

		[SerializeField]
		private GameObject errorField;

		private int currentPage;

		private int downloaded;

		private int failed;

		private readonly List<DownloadableTrackEntry> tracks = new List<DownloadableTrackEntry>();

		private readonly List<IEnumerator> downloadRoutines = new List<IEnumerator>();

		private Func<DownloadableTrackEntry, TracksDownloader, IEnumerator> downloadCallback;

		private Func<List<DownloadableTrackEntry>, TracksDownloader, List<IEnumerator>> downloadAllCallback;

		public event Action<string> URLChanged;

		private void Start()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			InputField component = urlField.GetComponent<InputField>();
			DelayedInputField component2 = urlField.GetComponent<DelayedInputField>();
			global::CybergrindMusicExplorer.Scripts.UI.Paginator component3 = paginator.GetComponent<global::CybergrindMusicExplorer.Scripts.UI.Paginator>();
			((UnityEvent)component3.previousButton.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				SetPage(currentPage - 1);
			});
			((UnityEvent)component3.nextButton.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				SetPage(currentPage + 1);
			});
			((UnityEvent)downloadAllButton.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				downloadAllButton.SetActive(false);
				ShowDownloadProgressMessage();
				downloadAllCallback(tracks, this).ForEach(delegate(IEnumerator routine)
				{
					downloadRoutines.Add(routine);
					((MonoBehaviour)this).StartCoroutine(routine);
				});
			});
			if (this.URLChanged != null)
			{
				component2.ValueChanged += this.URLChanged;
			}
			Rebuild();
			((UnityEvent<string>)(object)component.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				DisplayMessage(string.Empty);
				loadingRing.SetActive(false);
				downloadRoutines.ForEach((Action<IEnumerator>)base.StopCoroutine);
				downloadRoutines.Clear();
				downloaded = 0;
				failed = 0;
			});
		}

		public void SetDownloadCallback(Func<DownloadableTrackEntry, TracksDownloader, IEnumerator> callback)
		{
			downloadCallback = callback;
		}

		public void SetDownloadAllCallback(Func<List<DownloadableTrackEntry>, TracksDownloader, List<IEnumerator>> callback)
		{
			downloadAllCallback = callback;
		}

		public void LoadingStarted()
		{
			Clear();
			loadingRing.SetActive(true);
		}

		public void LoadingComplete()
		{
			loadingRing.SetActive(false);
		}

		public void ShowRestartButton()
		{
			restartButton.SetActive(true);
		}

		public void ShowDownloadAllButton()
		{
			downloadAllButton.SetActive(true);
		}

		public void HideDownloadAllButton()
		{
			downloadAllButton.SetActive(false);
		}

		public void DisplayMessage(string error)
		{
			loadingRing.SetActive(false);
			((TMP_Text)errorField.GetComponent<TextMeshProUGUI>()).text = error;
		}

		public void ShowDownloadProgressMessage()
		{
			DisplayMessage($"[<color=green>Downloaded</color>: {downloaded}/{tracks.Count}, <color=red>Failed</color>: {failed}/{tracks.Count}]");
		}

		public void IncreaseDownloaded()
		{
			downloaded++;
			ShowDownloadProgressMessage();
		}

		public void IncreaseFailed()
		{
			downloaded++;
			ShowDownloadProgressMessage();
		}

		public void AddEntry(DownloadableTrackMetadata metadata)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			if (metadata != null && metadata.Title != null)
			{
				DownloadableTrackEntry entry = Object.Instantiate<GameObject>(trackEntryPrefab, list.transform).GetComponent<DownloadableTrackEntry>();
				entry.Metadata = metadata;
				tracks.Add(entry);
				Rebuild();
				((UnityEvent)entry.statusBar.downloadButton.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
				{
					Download(entry);
				});
				((UnityEvent)entry.statusBar.retryButton.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
				{
					Download(entry);
				});
			}
		}

		public void SetPage(int page)
		{
			if ((tracks.Count <= 0 || page != 0) && page <= MaxPage())
			{
				currentPage = page;
				Rebuild();
			}
		}

		public void EasterEgg()
		{
			Object.Instantiate<GameObject>(easterEgg, list.transform);
		}

		private int MaxPage()
		{
			return (int)Math.Ceiling((double)tracks.Count / 20.0);
		}

		private void Rebuild()
		{
			currentPage = ((tracks.Count != 0) ? ((currentPage == 0) ? 1 : currentPage) : 0);
			for (int i = 0; i < tracks.Count; i++)
			{
				((Component)tracks[i]).gameObject.SetActive(i >= (currentPage - 1) * 20 && i < currentPage * 20);
			}
			paginator.GetComponent<global::CybergrindMusicExplorer.Scripts.UI.Paginator>().Refresh(currentPage, (int)Math.Ceiling((double)tracks.Count / 20.0));
		}

		private void Clear()
		{
			tracks.Clear();
			for (int i = 0; i < list.transform.childCount; i++)
			{
				Object.Destroy((Object)(object)((Component)list.transform.GetChild(i)).gameObject);
			}
			Rebuild();
		}

		private Coroutine Download(DownloadableTrackEntry entry)
		{
			return ((MonoBehaviour)this).StartCoroutine(downloadCallback(entry, this));
		}
	}
}
namespace CybergrindMusicExplorer.Scripts.Utils
{
	public static class Ffmpeg
	{
		private static readonly string FfmpegExecutableInnerPath = "ffmpeg-master-latest-win64-gpl/bin/ffmpeg.exe";

		private static readonly string FfprobeExecutableInnerPath = "ffmpeg-master-latest-win64-gpl/bin/ffprobe.exe";

		private const string FfmpegExecutable = "ffmpeg.exe";

		private const string FfprobeExecutable = "ffprobe.exe";

		private static readonly string CgmePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		private static readonly string FfmpegZip = Path.Combine(CgmePath, "ffmpeg.zip");

		private static readonly string FfmpegPath = Path.Combine(CgmePath, "ffmpeg.exe");

		private static readonly string FfprobePath = Path.Combine(CgmePath, "ffprobe.exe");

		private const string FfmpegArchivePath = "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip";

		public static bool FfmpegInstalled()
		{
			if (new FileInfo(FfmpegPath).Exists)
			{
				return new FileInfo(FfprobePath).Exists;
			}
			return false;
		}

		public static void InstallFfmpeg(FfmpegDownloadSection downloadSection)
		{
			downloadSection.StartDownloading();
			using WebClient webClient = new WebClient();
			webClient.Proxy = null;
			webClient.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e)
			{
				downloadSection.DownloadStatusUpdate(e.ProgressPercentage);
			};
			webClient.DownloadFileCompleted += delegate
			{
				UnzipFfmpeg(downloadSection);
			};
			try
			{
				webClient.DownloadFileAsync(new Uri("https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip"), FfmpegZip);
			}
			catch (Exception)
			{
				downloadSection.DownloadFailed();
			}
		}

		private static void UnzipFfmpeg(FfmpegDownloadSection downloadSection)
		{
			downloadSection.Unzipping();
			try
			{
				using (ZipArchive zipArchive = ZipFile.OpenRead(FfmpegZip))
				{
					ZipArchiveEntry source = zipArchive.Entries.First((ZipArchiveEntry e) => e.FullName.Equals(FfmpegExecutableInnerPath));
					ZipArchiveEntry source2 = zipArchive.Entries.First((ZipArchiveEntry e) => e.FullName.Equals(FfprobeExecutableInnerPath));
					source.ExtractToFile(Path.Combine(CgmePath, "ffmpeg.exe"), overwrite: true);
					source2.ExtractToFile(Path.Combine(CgmePath, "ffprobe.exe"), overwrite: true);
				}
				CleanupArchive();
				downloadSection.CheckFfmpegPresence();
			}
			catch (Exception)
			{
				downloadSection.DownloadFailed();
			}
		}

		private static void CleanupArchive()
		{
			System.IO.File.Delete(FfmpegZip);
		}
	}
}
namespace CybergrindMusicExplorer.Scripts.UI
{
	public class CgmeProgressBar : MonoBehaviour
	{
		[SerializeField]
		private GameObject bar;

		[SerializeField]
		private TextMeshProUGUI textValue;

		private void Start()
		{
			UpdateValue(0);
		}

		public void UpdateValue(int newValue)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)textValue).text = newValue + "%";
			bar.transform.localScale = new Vector3((float)newValue / 100f, 1f, 1f);
		}
	}
	public class DelayedInputField : MonoBehaviour
	{
		private Coroutine currentCoroutine;

		public event Action<string> ValueChanged;

		private void Awake()
		{
			((UnityEvent<string>)(object)((Component)this).gameObject.GetComponent<InputField>().onValueChanged).AddListener((UnityAction<string>)delegate(string value)
			{
				if (currentCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(currentCoroutine);
				}
				currentCoroutine = ((MonoBehaviour)this).StartCoroutine(DelayedTrigger(value));
			});
		}

		private IEnumerator DelayedTrigger(string value)
		{
			yield return (object)new WaitForSecondsRealtime(0.5f);
			if (this.ValueChanged != null)
			{
				this.ValueChanged(value);
			}
		}
	}
	public class DownloadableTrackEntry : MonoBehaviour
	{
		[SerializeField]
		private TextMeshProUGUI titleText;

		[SerializeField]
		private GameObject statusBarGo;

		[SerializeField]
		public Image preview;

		public DownloadStatusBar statusBar;

		private DownloadableTrackMetadata metadata;

		private DownloadableTrackEntryState state;

		public DownloadableTrackEntryState State
		{
			get
			{
				return state;
			}
			set
			{
				state = value;
				if (((Component)statusBar).gameObject.activeInHierarchy)
				{
					UpdateStatusBar(value);
				}
			}
		}

		public DownloadableTrackMetadata Metadata
		{
			get
			{
				return metadata;
			}
			set
			{
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Expected O, but got Unknown
				metadata = value;
				((TMP_Text)titleText).text = value.Title;
				if (!((Object)(object)value.Cover == (Object)null))
				{
					Texture cover = value.Cover;
					int num = cover.width - cover.height;
					int num2 = Math.Min(cover.width, cover.height);
					preview.sprite = Sprite.Create((Texture2D)cover, new Rect((float)Math.Max(num, 0) / 2f, (float)Math.Max(-num, 0) / 2f, (float)num2, (float)num2), new Vector2(0.5f, 0.5f), 100f);
				}
			}
		}

		private void Awake()
		{
			statusBar = statusBarGo.GetComponent<DownloadStatusBar>();
		}

		private void OnEnable()
		{
			((MonoBehaviour)this).StartCoroutine(Enable());
		}

		private IEnumerator Enable()
		{
			yield return (object)new WaitUntil((Func<bool>)(() => (Object)(object)statusBarGo != (Object)null && statusBarGo.activeInHierarchy));
			UpdateStatusBar(state);
		}

		public void DownloadProgress(int percentage)
		{
			if (((Component)statusBar).gameObject.activeInHierarchy)
			{
				statusBar.Downloading();
				statusBar.progressBar.UpdateValue(percentage);
			}
		}

		private void UpdateStatusBar(DownloadableTrackEntryState newState)
		{
			if (((Component)statusBar).gameObject.activeInHierarchy)
			{
				switch (newState)
				{
				case DownloadableTrackEntryState.Downloading:
					statusBar.Downloading();
					break;
				case DownloadableTrackEntryState.Enqueued:
					statusBar.Enqueued();
					break;
				case DownloadableTrackEntryState.Processing:
					statusBar.Processing();
					break;
				case DownloadableTrackEntryState.Downloaded:
					statusBar.Downloaded();
					break;
				case DownloadableTrackEntryState.Failed:
					statusBar.Failed();
					break;
				}
			}
		}
	}
	public class DownloadStatusBar : MonoBehaviour
	{
		[SerializeField]
		private GameObject progressBarGo;

		[SerializeField]
		public GameObject downloadButton;

		[SerializeField]
		public GameObject retryButton;

		[SerializeField]
		public GameObject statusLabel;

		public CgmeProgressBar progressBar;

		private TextMeshProUGUI statusLabelText;

		private void Start()
		{
			progressBar = progressBarGo.GetComponent<CgmeProgressBar>();
			statusLabelText = statusLabel.GetComponent<TextMeshProUGUI>();
		}

		public void Downloading()
		{
			downloadButton.SetActive(false);
			progressBarGo.SetActive(true);
			retryButton.SetActive(false);
			((Component)statusLabelText).gameObject.SetActive(false);
		}

		public void Enqueued()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			downloadButton.SetActive(false);
			progressBarGo.SetActive(false);
			statusLabel.SetActive(true);
			((TMP_Text)statusLabelText).text = "ENQUEUED";
			((Graphic)statusLabelText).color = Color.yellow;
		}

		public void Processing()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			downloadButton.SetActive(false);
			progressBarGo.SetActive(false);
			statusLabel.SetActive(true);
			((TMP_Text)statusLabelText).text = "PROCESSING";
			((Graphic)statusLabelText).color = Color.yellow;
		}

		public void Downloaded()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			downloadButton.SetActive(false);
			progressBarGo.SetActive(false);
			statusLabel.SetActive(true);
			((TMP_Text)statusLabelText).text = "DOWNLOADED";
			((Graphic)statusLabelText).color = Color.green;
		}

		public void Failed()
		{
			downloadButton.SetActive(false);
			progressBarGo.SetActive(false);
			retryButton.SetActive(true);
			((Component)statusLabelText).gameObject.SetActive(false);
		}
	}
	public class FfmpegDownloadSection : MonoBehaviour
	{
		[SerializeField]
		public GameObject menu;

		[SerializeField]
		public GameObject warning;

		[SerializeField]
		public GameObject downloadButton;

		[SerializeField]
		public GameObject progressBar;

		[SerializeField]
		public GameObject progressText;

		private void Awake()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			CheckFfmpegPresence();
			((UnityEvent)downloadButton.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				Ffmpeg.InstallFfmpeg(this);
			});
		}

		public void StartDownloading()
		{
			downloadButton.SetActive(false);
			progressBar.SetActive(true);
			progressText.SetActive(true);
			ChangeStatusMessage("Downloading...");
		}

		public void Unzipping()
		{
			progressBar.SetActive(false);
			ChangeStatusMessage("Unzipping...");
		}

		public void DownloadFailed()
		{
			progressBar.SetActive(false);
			ChangeStatusMessage("Download failed! Try again later.");
		}

		public void DownloadStatusUpdate(int percentage)
		{
			progressBar.GetComponent<CgmeProgressBar>().UpdateValue(percentage);
		}

		public void CheckFfmpegPresence()
		{
			if (Ffmpeg.FfmpegInstalled())
			{
				menu.SetActive(true);
				warning.SetActive(false);
			}
			else
			{
				menu.SetActive(false);
				warning.SetActive(true);
			}
		}

		private void ChangeStatusMessage(string msg)
		{
			((TMP_Text)progressText.GetComponent<TextMeshProUGUI>()).text = msg;
		}
	}
	public class Paginator : MonoBehaviour
	{
		[SerializeField]
		public GameObject previousButton;

		[SerializeField]
		public GameObject nextButton;

		[SerializeField]
		private GameObject pageText;

		public void Refresh(int currentPage, int pagesCount)
		{
			((TMP_Text)pageText.GetComponent<TextMeshProUGUI>()).text = $"{currentPage}/{pagesCount}";
		}
	}
	public class ShopButtonCallback : MonoBehaviour
	{
		private class InternalCallback : MonoBehaviour
		{
			private Action callback;

			private void OnEnable()
			{
				callback?.Invoke();
				((Component)this).gameObject.SetActive(false);
			}

			public void SetCallback(Action action)
			{
				callback = action;
			}
		}

		public GameObject callbackObject;

		public void SetCallback(Action callback)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			callbackObject = Object.Instantiate<GameObject>(new GameObject(), ((Component)this).transform);
			callbackObject.AddComponent<InternalCallback>().SetCallback(callback);
		}
	}
	public delegate void EndSliderDragEvent(float val);
	[RequireComponent(typeof(Slider))]
	public class SliderAndValue : MonoBehaviour, IPointerUpHandler, IEventSystemHandler
	{
		public TextMeshProUGUI value;

		public SliderEvent OnValueChanged => ((Component)this).gameObject.GetComponent<Slider>().onValueChanged;

		public float Value
		{
			set
			{
				((Component)this).gameObject.GetComponent<Slider>().value = value;
			}
		}

		private float SliderValue => ((Component)this).gameObject.GetComponent<Slider>().value;

		public event EndSliderDragEvent EndDrag;

		public void OnPointerUp(PointerEventData data)
		{
			if (this.EndDrag != null)
			{
				this.EndDrag(SliderValue);
			}
		}
	}
	public class TerminalBrowserConfirmationWindow : MonoBehaviour
	{
		[SerializeField]
		private GameObject warningMessage;

		[SerializeField]
		private GameObject acceptButton;

		[SerializeField]
		private GameObject declineButton;

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			((UnityEvent)declineButton.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				((Component)this).gameObject.SetActive(false);
			});
		}

		public void ShowWarning(string message, UnityAction action)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			((Component)this).gameObject.SetActive(true);
			((TMP_Text)warningMessage.GetComponent<TextMeshProUGUI>()).text = message;
			((UnityEventBase)acceptButton.GetComponent<Button>().onClick).RemoveAllListeners();
			((UnityEvent)acceptButton.GetComponent<Button>().onClick).AddListener(action);
			((UnityEvent)acceptButton.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				((Component)this).gameObject.SetActive(false);
			});
		}
	}
	public class TerminalBrowserWindow : MonoBehaviour
	{
		[SerializeField]
		public GameObject removeButton;

		[SerializeField]
		public GameObject confirmationWindow;
	}
}
namespace CybergrindMusicExplorer.Scripts.UI.Manual
{
	public class ManualSectionButton : MonoBehaviour
	{
		[SerializeField]
		private GameObject contents;

		[SerializeField]
		private GameObject contentsSections;

		[SerializeField]
		private GameObject viewport;

		[SerializeField]
		private ScrollRect scrollArea;

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			((UnityEvent)((Component)this).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				contentsSections.SetActive(true);
				((Component)((Component)this).transform.parent).gameObject.SetActive(false);
				foreach (Transform item in viewport.transform)
				{
					Object.Destroy((Object)(object)((Component)item).gameObject);
				}
				GameObject val = Object.Instantiate<GameObject>(contents, viewport.transform);
				scrollArea.content = val.GetComponent<RectTransform>();
				contents.SetActive(true);
			});
		}
	}
}
namespace CybergrindMusicExplorer.Scripts.Data
{
	public enum DownloadableTrackEntryState
	{
		Idle,
		Downloading,
		Enqueued,
		Processing,
		Downloaded,
		Failed
	}
	public class DownloadableTrackMetadata
	{
		public string Title { get; private set; }

		public Texture Cover { get; private set; }

		public string Url { get; private set; }

		public DownloadableTrackMetadata(string title, Texture cover, string trackUrl)
		{
			Title = title;
			Cover = cover;
			Url = trackUrl;
		}
	}
}
namespace CybergrindMusicExplorer.Patches
{
	[HarmonyPatch(typeof(AudioMixerController))]
	public class AudioMixerControllerPatch
	{
		private static CybergrindMusicExplorerManager _manager;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(AudioMixerController), "SetMusicVolume")]
		public static bool AudioMixerController_SetMusicVolume_Prefix(float volume, AudioMixerController __instance)
		{
			if ((Object)(object)_manager == (Object)null)
			{
				_manager = MonoSingleton<CybergrindMusicExplorerManager>.Instance;
			}
			float num = (_manager.allowMusicBoost ? _manager.CustomTracksBoost : 0f);
			if (!__instance.forceOff)
			{
				__instance.musicSound.SetFloat("allVolume", __instance.CalculateVolume(volume) + num);
			}
			__instance.musicVolume = volume;
			return false;
		}
	}
	[HarmonyPatch(typeof(CustomMusicPlayer))]
	public class CustomMusicPlayerPatch : MonoBehaviour
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(CustomMusicPlayer), "OnEnable")]
		public static bool CustomMusicPlayer_OnEnable_Prefix(CustomMusicPlayer __instance)
		{
			((Component)((Component)__instance).transform).gameObject.AddComponent<EnhancedMusicPlayer>();
			Object.Destroy((Object)(object)__instance);
			return false;
		}
	}
	[HarmonyPatch(typeof(CustomMusicPlaylistEditor))]
	public class CustomMusicPlaylistEditorPatch
	{
		private static readonly Dictionary<string, SongMetadata> MetadataCache = new Dictionary<string, SongMetadata>();

		private static GameObject clearButton;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(CustomMusicPlaylistEditor), "GetSongMetadataFromFilepath")]
		public static bool CustomMusicPlaylistEditor_GetSongMetadataFromFilepath_Prefix(SongIdentifier id, Sprite ___defaultIcon, ref SongMetadata __result)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			if (MetadataCache.TryGetValue(id.path, out var value))
			{
				__result = value;
				return false;
			}
			FileInfo fileInfo = new FileInfo(id.path);
			if (!fileInfo.Exists)
			{
				fileInfo = CustomTracksNamingUtil.WithPostfix(fileInfo, "intro");
			}
			if (!fileInfo.Exists)
			{
				__result = null;
				return false;
			}
			TagLib.Tag tag = TagLib.File.Create(fileInfo.FullName).Tag;
			Sprite val = MetadataUtils.GetAlbumCoverSprite(tag) ?? ___defaultIcon;
			StringBuilder stringBuilder = new StringBuilder(tag.Title ?? Path.GetFileNameWithoutExtension(CustomTracksNamingUtil.WithoutPostfix(fileInfo).FullName));
			if (tag.FirstPerformer != null)
			{
				stringBuilder.Append(" <color=#7f7f7f>");
				stringBuilder.Append(tag.FirstPerformer);
				stringBuilder.Append("</color>");
			}
			__result = new SongMetadata(stringBuilder.ToString(), val, 1);
			MetadataCache.Add(id.path, __result);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(CustomMusicPlaylistEditor), "LoadPlaylist")]
		public static bool CustomMusicPlaylistEditor_LoadPlaylist_Prefix(CustomMusicPlaylistEditor __instance)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			Playlist val;
			using (StreamReader streamReader = new StreamReader(System.IO.File.Open(Playlist.currentPath, FileMode.OpenOrCreate)))
			{
				val = JsonConvert.DeserializeObject<Playlist>(streamReader.ReadToEnd());
			}
			if (val == null)
			{
				return true;
			}
			Playlist val2 = new Playlist
			{
				selected = val.selected,
				loopMode = val.loopMode,
				shuffled = val.shuffled
			};
			foreach (SongIdentifier id in val.ids)
			{
				if ((int)id.type == 0 || new FileInfo(id.path).Exists)
				{
					val2.Add(id);
				}
			}
			__instance.playlist = val2;
			__instance.SavePlaylist();
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(CustomMusicPlaylistEditor), "Select")]
		public static void CustomMusicPlaylistEditor_Select_Postfix(int newIndex, bool rebuild, CustomMusicPlaylistEditor __instance)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (MonoSingleton<CybergrindMusicExplorerManager>.Instance.EnableTracksPreview && rebuild && MonoSingleton<FistControl>.Instance.shopping)
			{
				TracksLoader instance = MonoSingleton<TracksLoader>.Instance;
				SongIdentifier val = __instance.playlist.ids[newIndex];
				((MonoBehaviour)instance).StartCoroutine(((int)val.type == 0) ? instance.LoadSongData(val, LoadedPreviewCallback) : instance.LoadSongData(new FileInfo(val.path), LoadedPreviewCallback, delegate
				{
				}));
			}
			static void LoadedPreviewCallback(CustomSongData selectedSong)
			{
				Object.FindObjectOfType<ScreenZoneHelper>().PlayPreview(((SoundtrackSong)selectedSong).clips[0]);
			}
		}
	}
	[HarmonyPatch(typeof(FileDirectoryTree))]
	public class FileDirectoryTreePatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(FileDirectoryTree), "GetFilesRecursive")]
		public static bool FileDirectoryTree_GetFilesRecursive_Prefix(ref IEnumerable<FileInfo> __result, FileDirectoryTree __instance)
		{
			if (!__instance.realDirectory.FullName.StartsWith(PathsUtils.CustomSongsPath))
			{
				return true;
			}
			__result = __instance.children.Where((IDirectoryTree<FileInfo> child) => !IsSpecialEffectsFolder(child)).SelectMany((IDirectoryTree<FileInfo> child) => child.GetFilesRecursive()).Concat(__instance.files);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FileDirectoryTree), "Refresh")]
		public static bool FileDirectoryTree_Refresh_Prefix(FileDirectoryTree __instance)
		{
			if (!__instance.realDirectory.FullName.StartsWith(PathsUtils.CustomSongsPath))
			{
				return true;
			}
			__instance.realDirectory.Create();
			FileInfo[] files = __instance.realDirectory.GetFiles();
			List<IGrouping<string, FileInfo>> segmentedTracks = (from file in files.Where((FileInfo file) => CustomTracksNamingUtil.AudioTypesByExtension.Keys.Contains(file.Extension.ToLower())).Where(CustomTracksNamingUtil.IntroOrLoopPart)
				group file by CustomTracksNamingUtil.WithoutPostfix(file).FullName).Where(CustomTracksNamingUtil.HasIntroAndLoop).ToList();
			List<string> second = (from file in files
				where CustomTracksNamingUtil.AudioTypesByExtension.Keys.Contains(file.Extension.ToLower())
				select file into track
				where !CustomTracksNamingUtil.HasSpecialPostfix(track, "calmintro") && !CustomTracksNamingUtil.HasSpecialPostfix(track, "calmloop") && !CustomTracksNamingUtil.HasSpecialPostfix(track, "calm")
				select track.FullName into track
				where !(from t in segmentedTracks.SelectMany((IGrouping<string, FileInfo> t) => t)
					select t.FullName).Contains(track)
				select track).ToList();
			FileInfo[] value = (from track in segmentedTracks.Select((IGrouping<string, FileInfo> @group) => @group.Key).Concat(second)
				select new FileInfo(Path.Combine(PathsUtils.CustomSongsPath, track.Substring(PathsUtils.CustomSongsPath.Length + 1)))).ToArray();
			SetPrivate((IDirectoryTree)(object)__instance, "name", __instance.realDirectory.Name);
			SetPrivate((IDirectoryTree)(object)__instance, "children", (from dir in __instance.realDirectory.GetDirectories()
				where dir.FullName != PathsUtils.SpecialEffectsDirectory.FullName
				select dir).Select((Func<DirectoryInfo, FileDirectoryTree>)((DirectoryInfo dir) => new FileDirectoryTree(dir, (IDirectoryTree<FileInfo>)(object)__instance))));
			SetPrivate((IDirectoryTree)(object)__instance, "files", value);
			return false;
		}

		private static bool IsSpecialEffectsFolder(IDirectoryTree<FileInfo> dir)
		{
			if (dir.name == "CGME")
			{
				return dir.parent?.parent == null;
			}
			return false;
		}

		private static void SetPrivate(IDirectoryTree instance, string paramName, object value)
		{
			typeof(FileDirectoryTree).GetProperty(paramName).SetValue(instance, value, null);
		}
	}
	[HarmonyPatch(typeof(FinalCyberRank))]
	public class FinalCyberRankPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(FinalCyberRank), "GameOver")]
		public static bool FinalCyberRank_GameOver_Prefix()
		{
			EnhancedMusicPlayer enhancedMusicPlayer = (EnhancedMusicPlayer)(object)Object.FindObjectOfType(typeof(EnhancedMusicPlayer));
			if ((Object)(object)enhancedMusicPlayer != (Object)null)
			{
				enhancedMusicPlayer.StopPlaylist();
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(MusicChanger))]
	public class MusicChangerPatch
	{
		[HarmonyTranspiler]
		[HarmonyPatch(typeof(MusicChanger), "Change")]
		public static IEnumerable<CodeInstruction> MusicChanger_Change_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 0; i < list.Count; i++)
			{
				if (DestroyInstance(list[i]))
				{
					list.RemoveRange(i - 1, 2);
					break;
				}
			}
			return list;
		}

		private static bool DestroyInstance(CodeInstruction instruction)
		{
			if (instruction.opcode == OpCodes.Call)
			{
				return CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Method(typeof(Object), "Destroy", new Type[1] { typeof(Object) }, (Type[])null));
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(MusicManager))]
	public class MusicManagerPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(MusicManager), "StartMusic")]
		public static void MusicManager_StartMusic_Postfix()
		{
			MonoSingleton<CalmThemeManager>.Instance.SlowUpdate();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MusicManager), "PlayBattleMusic")]
		public static bool MusicManager_PlayBattleMusic_Prefix(MusicManager __instance)
		{
			if (!(new StackTrace().GetFrame(2).GetMethod().DeclaringType?.DeclaringType == typeof(CalmThemeManager)))
			{
				return false;
			}
			if (!__instance.dontMatch && (Object)(object)__instance.targetTheme != (Object)(object)__instance.battleTheme)
			{
				__instance.battleTheme.time = __instance.cleanTheme.time;
			}
			__instance.targetTheme = __instance.bossTheme;
			return false;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(MusicManager), "PlayBattleMusic")]
		public static IEnumerable<CodeInstruction> MusicManager_PlayBattleMusic_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 0; i < list.Count; i++)
			{
				if (EqualizeTimeCall(list[i]))
				{
					EqualizeTimeSamplesInstead(list, i);
					break;
				}
			}
			return list;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MusicManager), "PlayCleanMusic")]
		public static bool MusicManager_PlayCleanMusic_Prefix(MusicManager __instance)
		{
			if (new StackTrace().GetFrame(2).GetMethod().DeclaringType?.DeclaringType != typeof(CalmThemeManager))
			{
				return false;
			}
			if (!__instance.dontMatch && (Object)(object)__instance.targetTheme != (Object)(object)__instance.cleanTheme)
			{
				__instance.cleanTheme.time = __instance.bossTheme.time;
			}
			if ((double)__instance.battleTheme.volume == (double)__instance.volume)
			{
				__instance.cleanTheme.time = __instance.bossTheme.time;
			}
			bool num = (Object)(object)__instance.cleanTheme.clip == (Object)(object)__instance.battleTheme.clip;
			bool flag = (Object)(object)__instance.targetTheme == (Object)(object)__instance.cleanTheme;
			AudioSource targetTheme;
			if (num)
			{
				if (!flag)
				{
					goto IL_00d9;
				}
				targetTheme = __instance.bossTheme;
			}
			else
			{
				if (flag)
				{
					goto IL_00d9;
				}
				targetTheme = __instance.cleanTheme;
			}
			goto IL_00e0;
			IL_00d9:
			targetTheme = __instance.targetTheme;
			goto IL_00e0;
			IL_00e0:
			__instance.targetTheme = targetTheme;
			return false;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(MusicManager), "PlayCleanMusic")]
		public static IEnumerable<CodeInstruction> MusicManager_PlayCleanMusic_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 0; i < list.Count; i++)
			{
				if (EqualizeTimeCall(list[i]))
				{
					EqualizeTimeSamplesInstead(list, i);
					break;
				}
			}
			return list;
		}

		private static void EqualizeTimeSamplesInstead(List<CodeInstruction> codeInstructions, int replaceAt)
		{
			codeInstructions.RemoveRange(replaceAt, 2);
			codeInstructions.InsertRange(replaceAt, ReflectionUtils.IL((OpCodes.Callvirt, AccessTools.Method(typeof(AudioSource), "get_timeSamples", (Type[])null, (Type[])null)), (OpCodes.Callvirt, AccessTools.Method(typeof(AudioSource), "set_timeSamples", new Type[1] { typeof(int) }, (Type[])null))));
		}

		private static bool EqualizeTimeCall(CodeInstruction instruction)
		{
			if (instruction.opcode == OpCodes.Callvirt)
			{
				return CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Method(typeof(AudioSource), "get_time", (Type[])null, (Type[])null));
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(OptionsMenuToManager))]
	public class OptionsMenuToManagerPatch
	{
		private static Transform _optionsMenu;

		private static Transform _audioSettingsContent;

		private static Transform _sectionPrefab;

		private static Transform _note;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(OptionsMenuToManager), "OpenOptions")]
		public static bool OptionsMenuToManager_OnEnable_Prefix(OptionsMenuToManager __instance)
		{
			((TMP_Text)((Component)_note).GetComponent<TextMeshProUGUI>()).text = GetNote();
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(OptionsMenuToManager), "Start")]
		public static bool OptionsMenuToManager_Start_Prefix(OptionsMenuToManager __instance)
		{
			_optionsMenu = __instance.optionsMenu.transform;
			Prepare();
			CreateSection(_audioSettingsContent, "-- GENERAL --").SetSiblingIndex(0);
			CreateSection(_audioSettingsContent, "-- CYBERGRIND MUSIC EXPLORER --");
			_note = CreateSection(_audioSettingsContent, GetNote());
			((TMP_Text)((Component)_note).GetComponent<TextMeshProUGUI>()).fontSize = 16f;
			return true;
		}

		private static void Prepare()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			_audioSettingsContent = _optionsMenu.Find("Audio Options").Find("Image");
			_sectionPrefab = _optionsMenu.Find("HUD Options").Find("Scroll Rect (1)").Find("Contents")
				.Find("-- HUD Elements -- ");
			((Component)_audioSettingsContent).GetComponent<RectTransform>().offsetMax = new Vector2(300f, 160f);
		}

		private static Transform CreateSection(Transform parent, string text)
		{
			Transform obj = Object.Instantiate<Transform>(_sectionPrefab, parent);
			((Object)obj).name = text;
			((TMP_Text)((Component)obj).GetComponent<TextMeshProUGUI>()).text = text;
			return obj;
		}

		private static string GetNote()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			KeyCode val = (KeyCode)MonoSingleton<CybergrindMusicExplorerManager>.Instance.MenuBinding;
			return "Please press [<color=orange>" + ((object)(KeyCode)(ref val)).ToString() + "</color>] in Cybergrind to open CGME options";
		}
	}
	public static class Patches
	{
		private static readonly Harmony Harmony = new Harmony("Flazhik.ULTRAKILL.CybergrindMusicExplorer");

		public static void PatchOnStartOptionsMenu()
		{
			PatchRequest.PatchMethod(typeof(OptionsMenuToManager), "Start").WithPrefix(typeof(OptionsMenuToManagerPatch), "OptionsMenuToManager_Start_Prefix").Using(Harmony)
				.Once();
		}

		public static void PatchOnEnableOptionsMenu()
		{
			PatchRequest.PatchMethod(typeof(OptionsMenuToManager), "OpenOptions").WithPrefix(typeof(OptionsMenuToManagerPatch), "OptionsMenuToManager_OnEnable_Prefix").Using(Harmony)
				.Once();
		}

		public static void PatchAudioMixer()
		{
			PatchRequest.PatchMethod(typeof(AudioMixerController), "SetMusicVolume").WithPrefix(typeof(AudioMixerControllerPatch), "AudioMixerController_SetMusicVolume_Prefix").Using(Harmony)
				.Once();
		}

		public static void PatchMusicPlayer()
		{
			PatchRequest.PatchMethod(typeof(CustomMusicPlayer), "OnEnable").WithPrefix(typeof(CustomMusicPlayerPatch), "CustomMusicPlayer_OnEnable_Prefix").Using(Harmony)
				.Once();
		}

		public static void PatchMusicManager()
		{
			if (!(SceneHelper.CurrentScene != "Endless"))
			{
				PatchRequest.PatchMethod(typeof(MusicManager), "StartMusic").WithPostfix(typeof(MusicManagerPatch), "MusicManager_StartMusic_Postfix").Using(Harmony)
					.Once();
				PatchRequest.PatchMethod(typeof(MusicManager), "PlayBattleMusic").WithPrefix(typeof(MusicManagerPatch), "MusicManager_PlayBattleMusic_Prefix").WithTranspiler(typeof(MusicManagerPatch), "MusicManager_PlayBattleMusic_Transpiler")
					.Using(Harmony)
					.Once();
				PatchRequest.PatchMethod(typeof(MusicManager), "PlayCleanMusic").WithPrefix(typeof(MusicManagerPatch), "MusicManager_PlayCleanMusic_Prefix").WithTranspiler(typeof(MusicManagerPatch), "MusicManager_PlayCleanMusic_Transpiler")
					.Using(Harmony)
					.Once();
			}
		}

		public static void PatchMusicChanger()
		{
			if (!(SceneHelper.CurrentScene != "Endless"))
			{
				PatchRequest.PatchMethod(typeof(MusicChanger), "Change").WithTranspiler(typeof(MusicChangerPatch), "MusicChanger_Change_Transpiler").Using(Harmony)
					.Once();
			}
		}

		public static void PatchFinalCyberRank()
		{
			PatchRequest.PatchMethod(typeof(FinalCyberRank), "GameOver").WithPrefix(typeof(FinalCyberRankPatch), "FinalCyberRank_GameOver_Prefix").Using(Harmony)
				.Once();
		}

		public static void PatchCustomMusicPlaylistEditor()
		{
			PatchRequest.PatchMethod(typeof(CustomMusicPlaylistEditor), "GetSongMetadataFromFilepath").WithPrefix(typeof(CustomMusicPlaylistEditorPatch), "CustomMusicPlaylistEditor_GetSongMetadataFromFilepath_Prefix").Using(Harmony)
				.Once();
			PatchRequest.PatchMethod(typeof(CustomMusicPlaylistEditor), "LoadPlaylist").WithPrefix(typeof(CustomMusicPlaylistEditorPatch), "CustomMusicPlaylistEditor_LoadPlaylist_Prefix").Using(Harmony)
				.Once();
			PatchRequest.PatchMethod(typeof(CustomMusicPlaylistEditor), "Select").WithPostfix(typeof(CustomMusicPlaylistEditorPatch), "CustomMusicPlaylistEditor_Select_Postfix").Using(Harmony)
				.Once();
		}

		public static void PatchPlaylist()
		{
			PatchRequest.PatchMethod(typeof(Playlist), "Add").WithPrefix(typeof(PlaylistPatch), "Playlist_Add_Prefix").Using(Harmony)
				.Once();
			PatchRequest.PatchMethod(typeof(Playlist), "get_currentPath").WithPrefix(typeof(PlaylistPatch), "Playlist_get_currentPath_Prefix").Using(Harmony)
				.Once();
		}

		public static void PatchDirectoryTree()
		{
			PatchRequest.PatchMethod(typeof(FileDirectoryTree), "GetFilesRecursive").WithPrefix(typeof(FileDirectoryTreePatch), "FileDirectoryTree_GetFilesRecursive_Prefix").Using(Harmony)
				.Once();
			PatchRequest.PatchMethod(typeof(FileDirectoryTree), "Refresh").WithPrefix(typeof(FileDirectoryTreePatch), "FileDirectoryTree_Refresh_Prefix").Using(Harmony)
				.Once();
		}

		public static void PatchWaveMenu()
		{
			PatchRequest.PatchMethod(typeof(WaveMenu), "Start").WithPostfix(typeof(WaveMenuPatch), "WaveMenu_Start_Postfix").Using(Harmony)
				.Once();
		}

		public static void PatchScreenZone()
		{
			PatchRequest.PatchMethod(typeof(ScreenZone), "Update").WithPrefix(typeof(ScreenZonePatch), "ScreenZone_Update_Prefix").Using(Harmony)
				.Once();
		}
	}
	[HarmonyPatch(typeof(Playlist))]
	public class PlaylistPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Playlist), "Add")]
		public static bool Playlist_Add_Prefix(SongIdentifier id, Playlist __instance)
		{
			if (MonoSingleton<CybergrindMusicExplorerManager>.Instance.PreventDuplicateTracks)
			{
				return !__instance.ids.Contains(id);
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		public static bool Playlist_get_currentPath_Prefix(ref string __result)
		{
			string text = Path.Combine(Playlist.directory.Parent.FullName, "Playlist.json");
			string text2 = Path.Combine(Playlist.directory.FullName, "slot" + MonoSingleton<CybergrindMusicExplorerManager>.Instance.SelectedPlaylistSlot + ".json");
			if (System.IO.File.Exists(text) && !System.IO.File.Exists(text2))
			{
				System.IO.File.Move(text, text2);
			}
			__result = text2;
			return false;
		}
	}
	[HarmonyPatch(typeof(ScreenZone))]
	public class ScreenZonePatch
	{
		private static ScreenZoneHelper helper;

		private static ScreenZone cgTerminal;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ScreenZone), "Update")]
		public static bool ScreenZone_Update_Prefix(bool ___inZone, ScreenZone __instance)
		{
			if ((Object)(object)cgTerminal == (Object)null)
			{
				if (!((Object)__instance).name.Equals("CyberGrindSettings"))
				{
					return true;
				}
				cgTerminal = __instance;
			}
			if ((Object)(object)cgTerminal != (Object)(object)__instance)
			{
				return true;
			}
			if ((Object)(object)helper == (Object)null)
			{
				ScreenZoneHelper screenZoneHelper = default(ScreenZoneHelper);
				if (!((Component)__instance).TryGetComponent<ScreenZoneHelper>(ref screenZoneHelper))
				{
					return true;
				}
				helper = screenZoneHelper;
			}
			helper.inZone = ___inZone;
			return true;
		}
	}
	[HarmonyPatch(typeof(WaveMenu))]
	public class WaveMenuPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(WaveMenu), "Start")]
		public static void WaveMenu_Start_Postfix(WaveMenu __instance)
		{
			((Component)__instance).gameObject.AddComponent<ScreenZoneHelper>();
		}
	}
}
namespace CybergrindMusicExplorer.GUI
{
	public class GUIManager : MonoSingleton<GUIManager>
	{
		public static CgmeMenuDeployer GUIDeployer;

		public static void Init()
		{
			SceneManager.sceneLoaded += OnSceneLoad;
		}

		private static void OnSceneLoad(Scene scene, LoadSceneMode mode)
		{
			if (!(SceneHelper.CurrentScene != "Endless"))
			{
				Prepare();
			}
		}

		private static void Prepare()
		{
			CanvasController instance = MonoSingleton<CanvasController>.Instance;
			CgmeMenuDeployer cgmeMenuDeployer = default(CgmeMenuDeployer);
			GUIDeployer = ((!((Component)instance).TryGetComponent<CgmeMenuDeployer>(ref cgmeMenuDeployer)) ? ((Component)instance).gameObject.AddComponent<CgmeMenuDeployer>() : cgmeMenuDeployer);
		}
	}
	public class CgmeMenuDeployer : MonoBehaviour
	{
		[PrefabAsset("assets/ui/cgmemenu.prefab")]
		private static GameObject menuPrefab;

		[PrefabAsset("assets/ui/playbackwindow.prefab")]
		private static GameObject playbackPrefab;

		[PrefabAsset("assets/ui/terminalbrowserwindow.prefab")]
		private static GameObject terminalBrowserPrefab;

		[PrefabAsset("assets/ui/playlistterminalbrowserwindow.prefab")]
		private static GameObject playlistTerminalBrowserPrefab;

		public GameObject playbackWindow;

		public GameObject terminalBrowserWindow;

		public GameObject terminalPlaylistWindow;

		private GameObject menuWindow;

		private GameObject canvas;

		private GameObject browserCanvas;

		private GameObject playlistCanvas;

		private readonly OptionsManager optionsManager = MonoSingleton<OptionsManager>.Instance;

		private readonly GameStateManager gameStateManager = GameStateManager.Instance;

		private readonly CameraController cameraController = MonoSingleton<CameraController>.Instance;

		private readonly CybergrindMusicExplorerManager manager = MonoSingleton<CybergrindMusicExplorerManager>.Instance;

		private readonly NewMovement newMovement = MonoSingleton<NewMovement>.Instance;

		private readonly GunControl gunControl = MonoSingleton<GunControl>.Instance;

		private void Awake()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			canvas = new GameObject
			{
				name = "CgmeCanvas"
			};
			canvas.AddComponent<Canvas>();
			Canvas component = canvas.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = GameObject.Find("/Canvas").GetComponent<Canvas>().sortingOrder + 1;
			canvas.AddComponent<CanvasScaler>();
			canvas.AddComponent<GraphicRaycaster>();
			browserCanvas = GameObject.Find("/FirstRoom/Room/CyberGrindSettings/Canvas/CustomMusic/Panel");
			playlistCanvas = GameObject.Find("/FirstRoom/Room/CyberGrindSettings/Canvas/Playlist/Panel");
			menuWindow = Object.Instantiate<GameObject>(menuPrefab, canvas.transform);
			playbackWindow = Object.Instantiate<GameObject>(playbackPrefab, canvas.transform);
			Upscale();
			terminalBrowserWindow = Object.Instantiate<GameObject>(terminalBrowserPrefab, browserCanvas.transform);
			Transform transform = terminalBrowserWindow.transform;
			transform.localPosition -= new Vector3(0f, 0f, 40f);
			terminalPlaylistWindow = Object.Instantiate<GameObject>(playlistTerminalBrowserPrefab, playlistCanvas.transform);
			Transform transform2 = terminalPlaylistWindow.transform;
			transform2.localPosition -= new Vector3(0f, 0f, 40f);
			CgmeMenuController cgmeMenuController = default(CgmeMenuController);
			if (!menuWindow.TryGetComponent<CgmeMenuController>(ref cgmeMenuController))
			{
				CgmeMenuController cgmeMenuController2 = menuWindow.AddComponent<CgmeMenuController>();
				menuWindow.AddComponent<HudOpenEffect>();
				playbackWindow.AddComponent<HudOpenEffect>();
				cgmeMenuController2.OnClose += delegate
				{
					if (menuWindow.activeSelf)
					{
						CloseOptionsMenu();
					}
				};
				cgmeMenuController2.OnScaled += delegate(float percentage)
				{
					//IL_001c: 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)
					float num = 1f + percentage / 100f;
					menuWindow.transform.localScale = new Vector3(num, num, num);
					playbackWindow.transform.localScale = new Vector3(num, num, num);
				};
			}
			TerminalBrowserController terminalBrowserController = default(TerminalBrowserController);
			if (!terminalBrowserWindow.TryGetComponent<TerminalBrowserController>(ref terminalBrowserController))
			{
				terminalBrowserWindow.AddComponent<TerminalBrowserController>();
				terminalBrowserWindow.AddComponent<HudOpenEffect>();
			}
			TerminalPlaylistController terminalPlaylistController = default(TerminalPlaylistController);
			if (!terminalPlaylistWindow.TryGetComponent<TerminalPlaylistController>(ref terminalPlaylistController))
			{
				terminalPlaylistWindow.AddComponent<TerminalPlaylistController>();
				terminalPlaylistWindow.AddComponent<HudOpenEffect>();
			}
			menuWindow.SetActive(false);
		}

		public void Update()
		{
			if (GameIsPaused())
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				if (menuWindow.activeSelf)
				{
					CloseOptionsMenu();
				}
				if (playbackWindow.activeSelf)
				{
					ClosePlaybackMenu();
				}
			}
			if (Input.GetKeyDown((KeyCode)manager.MenuBinding))
			{
				if (playbackWindow.activeSelf)
				{
					return;
				}
				if (!menuWindow.activeSelf)
				{
					OpenOptionsMenu();
				}
				else
				{
					CloseOptionsMenu();
				}
			}
			if (Input.GetKeyDown((KeyCode)manager.PlaybackMenuBinding))
			{
				if (!playbackWindow.activeSelf)
				{
					OpenPlaybackMenu();
				}
				else
				{
					ClosePlaybackMenu();
				}
			}
		}

		public void OpenOptionsMenu()
		{
			menuWindow.SetActive(true);
			Pause("cgmeMenu", menuWindow);
		}

		public void CloseOptionsMenu()
		{
			menuWindow.SetActive(false);
			UnPause("cgmeMenu");
		}

		public void OpenPlaybackMenu()
		{
			playbackWindow.SetActive(true);
			Pause("cgmePlayback", playbackWindow);
		}

		public void ClosePlaybackMenu()
		{
			playbackWindow.SetActive(false);
			UnPause("cgmePlayback");
		}

		private void Upscale()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			float num = 1f + manager.MenuUpscale / 100f;
			menuWindow.transform.localScale = new Vector3(num, num, num);
			playbackWindow.transform.localScale = new Vector3(num, num, num);
		}

		private void Pause(string stateKey, GameObject window)
		{
			//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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			((Behaviour)newMovement).enabled = false;
			cameraController.activated = false;
			gunControl.activated = false;
			gameStateManager.RegisterState(new GameState(stateKey, (GameObject[])(object)new GameObject[1] { window })
			{
				cursorLock = (LockMode)2,
				cameraInputLock = (LockMode)1,
				playerInputLock = (LockMode)1
			});
			optionsManager.paused = true;
		}

		private void UnPause(string stateKey)
		{
			gameStateManager.PopState(stateKey);
			if (!menuWindow.activeSelf && !playbackWindow.activeSelf)
			{
				Time.timeScale = MonoSingleton<TimeController>.Instance.timeScale * MonoSingleton<TimeController>.Instance.timeScaleModifier;
				optionsManager.paused = false;
				cameraController.activated = true;
				((Behaviour)newMovement).enabled = true;
				gunControl.activated = true;
			}
		}

		private bool GameIsPaused()
		{
			return gameStateManager.IsStateActive("pause");
		}
	}
}
namespace CybergrindMusicExplorer.GUI.Elements
{
	public class ControlBinding : MonoBehaviour
	{
		public Button button;

		public TextMeshProUGUI value;
	}
	[UICustomElement("CGMECounter")]
	public class Counter : MonoBehaviour
	{
		private int tmpValue;

		public TextMeshProUGUI textValue;

		public CounterButton increase;

		public CounterButton decrease;

		private IEnumerator changeValueRoutine;

		public int Value { get; private set; }

		public event Action<int> OnChanged;

		public void Init(CounterButton increaseButton, CounterButton decreaseButton)
		{
			increase = increaseButton;
			decrease = decreaseButton;
			AddEvents(increase, delegate
			{
				tmpValue = ChangeValue((int i) => i + 1);
			});
			AddEvents(decrease, delegate
			{
				tmpValue = ChangeValue((int i) => i - 1);
			});
		}

		public void SetDefaultValue(int defaultValue)
		{
			Value = defaultValue;
			tmpValue = defaultValue;
			((TMP_Text)textValue).text = defaultValue.ToString();
		}

		private void AddEvents(CounterButton button, Action<int> callback)
		{
			button.OnDown += delegate
			{
				changeValueRoutine = ChangeValueRoutine(callback);
				((MonoBehaviour)this).StartCoroutine(changeValueRoutine);
			};
			button.OnUp += SaveValue;
			button.OnExit += SaveValue;
		}

		private void SaveValue()
		{
			if (changeValueRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(changeValueRoutine);
			}
			Value = tmpValue;
			((TMP_Text)textValue).text = Value.ToString();
			this.OnChanged?.Invoke(Value);
		}

		private IEnumerator ChangeValueRoutine(Action<int> callback)
		{
			callback(tmpValue);
			yield return (object)new WaitForSecondsRealtime(0.3f);
			while (true)
			{
				callback(tmpValue);
				yield return (object)new WaitForSecondsRealtime(0.1f);
			}
		}

		private int ChangeValue(Func<int, int> operation)
		{
			int result = ValidateOperation(operation);
			((TMP_Text)textValue).text = result.ToString();
			return result;
		}

		private int ValidateOperation(Func<int, int> operation)
		{
			int num = operation(tmpValue);
			if (num < 0 || num > 99)
			{
				return tmpValue;
			}
			return num;
		}
	}
	public class CounterButton : Button
	{
		public bool pressed;

		public event Action OnDown;

		public event Action OnUp;

		public event Action OnExit;

		public override void OnPointerDown(PointerEventData eventData)
		{
			pressed = true;
			((Selectable)this).OnPointerDown(eventData);
			this.OnDown?.Invoke();
		}

		public override void OnPointerUp(PointerEventData eventData)
		{
			pressed = false;
			((Selectable)this).OnPointerUp(eventData);
			this.OnUp?.Invoke();
		}

		public override void OnPointerExit(PointerEventData eventData)
		{
			((Selectable)this).OnPointerExit(eventData);
			if (pressed)
			{
				this.OnExit?.Invoke();
			}
			pressed = false;
		}
	}
	[AttributeUsage(AttributeTargets.Class)]
	public class UICustomElement : Attribute
	{
		public string GameObjectName { get; }

		public UICustomElement(string goName = "")
		{
			GameObjectName = goName;
		}
	}
}
namespace CybergrindMusicExplorer.GUI.Controllers
{
	public class CgmeMenuController : UIController
	{
		private const string ThunderUrl = "https://thunderstore.io/package/download/Flazhik/CybergrindMusicExplorer";

		private const string GithubUrl = "https://github.com/Flazhik/CybergrindMusicExplorer/releases/download";

		private readonly PrefsManager prefsManager = MonoSingleton<PrefsManager>.Instance;

		private readonly OptionsMenuToManager optionsManager = MonoSingleton<OptionsMenuToManager>.Instance;

		private readonly AudioMixerController mixer = MonoSingleton<AudioMixerController>.Instance;

		private readonly TracksDownloadManager tracksDownloadManager = MonoSingleton<TracksDownloadManager>.Instance;

		private CalmThemeManager calmThemeManager;

		[PrefabAsset("assets/ui/elements/enemycounter.prefab")]
		private static GameObject enemyCounterPrefab;

		[HudEffect]
		[UIElement("Header/Tab")]
		private GameObject tabName;

		[HudEffect]
		[UIElement("Menu/General")]
		private GameObject general;

		[HudEffect]
		[UIElement("Menu/Bindings")]
		private GameObject bindings;

		[HudEffect]
		[UIElement("Menu/Themes")]
		private GameObject themes;

		[HudEffect]
		[UIElement("Menu/Downloader")]
		private TracksDownloader tracksDownloader;

		[HudEffect]
		[UIElement("Menu/Manual")]
		private GameObject manual;

		[HudEffect]
		[UIElement("Menu/Credits")]
		private GameObject credits;

		[UIElement("Menu/General/ListControl/ScrollArea/Mask/Viewport/List/InfinitePanel/Controller/Checkbox")]
		private Toggle showPanelIndefinitely;

		[UIElement("Menu/General/ListControl/ScrollArea/Mask/Viewport/List/EnablePreview/Controller/Checkbox")]
		private Toggle enablePreview;

		[UIElement("Menu/General/ListControl/ScrollArea/Mask/Viewport/List/Subtitles/Controller/Checkbox")]
		private Toggle subtitles;

		[UIElement("Menu/General/ListControl/ScrollArea/Mask/Viewport/List/Boost/Controller/Slider/Slider")]
		private SliderAndValue boost;

		[UIElement("Menu/General/ListControl/ScrollArea/Mask/Viewport/List/Scale/Controller/Slider/Slider")]
		private SliderAndValue scale;

		[UIElement("Menu/General/ListControl/ScrollArea/Mask/Viewport/List/BigNowPlayingPanel/Controller/Checkbox")]
		private Toggle bigNowPlayingPanel;

		[UIElement("Menu/General/ListControl/ScrollArea/Mask/Viewport/List/PreventDuplicates/Controller/Checkbox")]
		private Toggle preventDuplicates;

		[UIElement("Menu/Bindings/ShowMenuHotkey/Controller/CGMEMenu")]
		private ControlBinding showMenuHotkey;

		[UIElement("Menu/Bindings/NextTrackHotkey/Controller/CGMENextTrack")]
		private ControlBinding nextTrackHotkey;

		[UIElement("Menu/Bindings/PlaybackHotkey/Controller/CGMEPlaybackMenu")]
		private ControlBinding playbackHotkey;

		[UIElement("Menu/Bindings/DisablePlayerHotkey/Controller/CGMEDisablePlayer")]
		private ControlBinding displayPlayerHotkey;

		[UIElement("Menu/Themes/EnableCalmTheme/Controller/Checkbox")]
		private Toggle calmTheme;

		[UIElement("Menu/Themes/EnemiesThreshold/Controller/Counter")]
		private Counter enemiesThreshold;

		[UIElement("Menu/Themes/CalmThemeSettings/ListControl/Scrollbar")]
		private Scrollbar specialEnemiesScrollbar;

		[UIElement("Menu/Themes/CalmThemeSettings/ListControl/ScrollArea/Mask/Viewport/List")]
		private GameObject specialEnemiesList;

		[UIElement("ThunderDownload")]
		private Button thunderDownload;

		[UIElement("GithubDownload")]
		private Button githubDownload;

		[UIElement("Version")]
		private TextMeshProUGUI version;

		[UIElement("Close")]
		private Button close;

		private Coroutine downloaderCoroutine;

		public event Action OnClose;

		public event EndSliderDragEvent OnScaled;

		private new void Awake()
		{
			base.Awake();
			((MonoBehaviour)this).StartCoroutine(Startup());
		}

		private IEnumerator Startup()
		{
			while ((Object)(object)MonoSingleton<CalmThemeManager>.Instance == (Object)null || !MonoSingleton<CalmThemeManager>.Instance.loaded)
			{
				yield return null;
			}
			calmThemeManager = MonoSingleton<CalmThemeManager>.Instance;
			((UnityEvent)close.onClick).AddListener((UnityAction)delegate
			{
				this.OnClose?.Invoke();
			});
			BindControls();
			BindHotkeys();
			SetupThemes();
			SetupDownloader();
			SetupSpecialEnemiesControls();
			HandleCurrentVersion();
		}

		private void BindControls()
		{
			showPanelIndefinitely.isOn = Manager.ShowCurrentTrackPanelIndefinitely;
			((UnityEvent<bool>)(object)showPanelIndefinitely.onValueChanged).AddListener((UnityAction<bool>)delegate(bool state)
			{
				Manager.ShowCurrentTrackPanelIndefinitely = state;
			});
			enablePreview.isOn = Manager.EnableTracksPreview;
			((UnityEvent<bool>)(object)enablePreview.onValueChanged).AddListener((UnityAction<bool>)delegate(bool state)
			{
				Manager.EnableTracksPreview = state;
			});
			bigNowPlayingPanel.isOn = Manager.ShowBigNowPlayingPanel;
			((UnityEvent<bool>)(object)bigNowPlayingPanel.onValueChanged).AddListener((UnityAction<bool>)delegate(bool state)
			{
				Manager.ShowBigNowPlayingPanel = state;
			});
			subtitles.isOn = prefsManager.GetBool("subtitlesEnabled", false);
			((UnityEvent<bool>)(object)subtitles.onValueChanged).AddListener((UnityAction<bool>)delegate(bool state)
			{
				optionsManager.SetSubtitles(state);
			});
			((TMP_Text)boost.value).text = $"+{Manager.CustomTracksBoost}dB";
			boost.Value = Manager.CustomTracksBoost;
			((UnityEvent<float>)(object)boost.OnValueChanged).AddListener((UnityAction<float>)delegate(float value)
			{
				((TMP_Text)boost.value).text = $"+{value}dB";
				Manager.CustomTracksBoost = value;
				mixer.SetMusicVolume(mixer.musicVolume);
			});
			((TMP_Text)scale.value).text = $"{Manager.MenuUpscale}%";
			scale.Value = Manager.MenuUpscale;
			((UnityEvent<float>)(object)scale.OnValueChanged).AddListener((UnityAction<float>)delegate(float value)
			{
				((TMP_Text)scale.value).text = $"{value}%";
			});
			scale.EndDrag += delegate(float value)
			{
				Manager.MenuUpscale = value;
			};
			scale.EndDrag += delegate(float value)
			{
				this.OnScaled?.Invoke(value);
			};
			preventDuplicates.isOn = Manager.PreventDuplicateTracks;
			((UnityEvent<bool>)(object)preventDuplicates.onValueChanged).AddListener((UnityAction<bool>)delegate(bool state)
			{
				Manager.PreventDuplicateTracks = state;
				if (state)
				{
					CustomMusicPlaylistEditor playlistEditor = CybergrindMusicExplorer.GetPlaylistEditor();
					Playlist playlist = playlistEditor.playlist;
					List<SongIdentifier> list = new List<SongIdentifier>();
					for (int i = 0; playlist.ids.ElementAtOrDefault(i) != null; i++)
					{
						if (list.Contains(playlist.ids[i]))
						{
							playlist.Remove(i);
							i--;
						}
						else
						{
							list.Add(playlist.ids[i]);
						}
					}
					((DirectoryTreeBrowser<SongIdentifier>)(object)playlistEditor).Rebuild(true);
				}
			});
		}

		private void BindHotkeys()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			((UnityEvent)showMenuHotkey.button.onClick).AddListener((UnityAction)delegate
			{
				ChangeKey(((Component)showMenuHotkey.button).gameObject);
			});
			((TMP_Text)showMenuHotkey.value).text = KeyUtils.ToHumanReadable((KeyCode)Manager.MenuBinding);
			((UnityEvent)nextTrackHotkey.button.onClick).AddListener((UnityAction)delegate
			{
				ChangeKey(((Component)nextTrackHotkey.button).gameObject);
			});
			((TMP_Text)nextTrackHotkey.value).text = KeyUtils.ToHumanReadable((KeyCode)Manager.NextTrackBinding);
			((UnityEvent)playbackHotkey.button.onClick).AddListener((UnityAction)delegate
			{
				ChangeKey(((Component)playbackHotkey.button).gameObject);
			});
			((TMP_Text)playbackHotkey.value).text = KeyUtils.ToHumanReadable((KeyCode)Manager.PlaybackMenuBinding);
			((UnityEvent)displayPlayerHotkey.button.onClick).AddListener((UnityAction)delegate
			{
				ChangeKey(((Component)displayPlayerHotkey.button).gameObject);
			});
			((TMP_Text)displayPlayerHotkey.value).text = KeyUtils.ToHumanReadable((KeyCode)Manager.DisablePlayerBinding);
		}

		private void SetupThemes()
		{
			calmTheme.isOn = Manager.PlayCalmTheme;
			((UnityEvent<bool>)(object)calmTheme.onValueChanged).AddListener((UnityAction<bool>)delegate(bool value)
			{
				Manager.PlayCalmTheme = value;
			});
			enemiesThreshold.SetDefaultValue(Manager.CalmThemeEnemiesThreshold);
			enemiesThreshold.OnChanged += delegate(int newValue)
			{
				Manager.CalmThemeEnemiesThreshold = newValue;
			};
		}

		private void SetupDownloader()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			tracksDownloader.SetDownloadCallback((DownloadableTrackEntry entry, TracksDownloader downloader) => tracksDownloadManager.Download(entry, downloader));
			tracksDownloader.SetDownloadAllCallback((List<DownloadableTrackEntry> entries, TracksDownloader downloader) => tracksDownloadManager.DownloadAll(entries.Where((DownloadableTrackEntry e) => e.State == DownloadableTrackEntryState.Idle).ToList(), downloader));
			tracksDownloader.URLChanged += delegate(string url)
			{
				tracksDownloadManager.Cancel();
				if (!tracksDownloadManager.SupportsUrl(url))
				{
					tracksDownloader.DisplayMessage("URL is invalid or not supported");
				}
				else
				{
					tracksDownloader.LoadingStarted();
					if (downloaderCoroutine != null)
					{
						((MonoBehaviour)this).StopCoroutine(downloaderCoroutine);
					}
					downloaderCoroutine = ((MonoBehaviour)this).StartCoroutine(OnUrlChangedCoroutine(url));
				}
			};
			((UnityEvent)tracksDownloader.restartButton.GetComponent<Button>().onClick).AddListener(new UnityAction(SceneHelper.RestartScene));
		}

		private IEnumerator OnUrlChangedCoroutine(string url)
		{
			tracksDownloader.HideDownloadAllButton();
			if (!tracksDownloadManager.SupportsUrl(url))
			{
				tracksDownloader.DisplayMessage("URL is invalid or not supported");
				yield break;
			}
			tracksDownloader.LoadingStarted();
			List<DownloadableTrackMetadata> metadataList = new List<DownloadableTrackMetadata>();
			yield return tracksDownloadManager.GetMetadata(url, delegate(DownloadableTrackMetadata metadata)
			{
				try
				{
					metadataList.Add(metadata);
					tracksDownloader.AddEntry(metadata);
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("An error has occured while receiving metadata for URL " + url + ": " + ex.Message));
				}
			}, tracksDownloader);
			tracksDownloader.LoadingComplete();
		}

		private void SetupSpecialEnemiesControls()
		{
			Dictionary<EnemyType, Sprite> sprites = SpecialEnemies.LoadEnemiesSprites();
			SpecialEnemies.SpecialEnemiesNames.ToList().ForEach(delegate(KeyValuePair<EnemyType, string> pair)
			{
				//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_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
				//IL_010f: Unknown result type (might be due to invalid IL or missing references)
				EnemyType enemyType = pair.Key;
				GameObject val = Object.Instantiate<GameObject>(enemyCounterPrefab, specialEnemiesList.transform);
				((TMP_Text)((Component)val.transform.Find("EnemyName")).GetComponent<TextMeshProUGUI>()).text = pair.Value;
				Image component = ((Component)val.transform.Find("Image")).GetComponent<Image>();
				((Graphic)component).color = Color.white;
				component.sprite = sprites[enemyType];
				BindCustomControllers(val);
				Counter counter = ((Component)val.transform.Find("CGMECounter")).GetComponent<Counter>();
				Toggle component2 = ((Component)val.transform.Find("Checkbox")).GetComponent<Toggle>();
				bool flag = calmThemeManager.Preferences.CalmTheme.SpecialEnemies.ContainsKey(enemyType);
				int defaultValue = (flag ? calmThemeManager.Preferences.CalmTheme.SpecialEnemies[enemyType] : 0);
				counter.SetDefaultValue(defaultValue);
				counter.OnChanged += delegate(int value)
				{
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					calmThemeManager.ChangeEnemyThreshold(enemyType, value);
				};
				component2.isOn = flag;
				((UnityEvent<bool>)(object)component2.onValueChanged).AddListener((UnityAction<bool>)delegate(bool value)
				{
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					calmThemeManager.ToggleSpecialEnemy(enemyType, value, counter.Value);
				});
			});
		}

		private void HandleCurrentVersion()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			System.Version version = System.Version.Parse("1.6.3");
			System.Version newestVersion = CybergrindMusicExplorer.GetNewestVersion();
			if (newestVersion > version)
			{
				string stringVersion = newestVersion.ToString(3);
				string text = (R2ModmanIsRunning() ? "Update via r2modman or from:" : "Click to download from:");
				((TMP_Text)this.version).text = "<color=#a8a8a8>Version " + stringVersion + " is available! " + text + "</color>\n<color=#3498db>Thunderstore</color> <color=#a8a8a8>|</color> <color=#f5f5f5>GitHub</color>";
				((Component)thunderDownload).gameObject.SetActive(true);
				((Component)githubDownload).gameObject.SetActive(true);
				((UnityEvent)thunderDownload.onClick).AddListener((UnityAction)delegate
				{
					DownloadNewestVersion("https://thunderstore.io/package/download/Flazhik/CybergrindMusicExplorer/" + stringVersion + "/");
				});
				((UnityEvent)githubDownload.onClick).AddListener((UnityAction)delegate
				{
					DownloadNewestVersion("https://github.com/Flazhik/CybergrindMusicExplorer/releases/download/v" + stringVersion + "/CybergrindMusicExplorer.v" + stringVersion + ".zip");
				});
			}
			else
			{
				((TMP_Text)this.version).text = "<color=#545454>Version " + version.ToString(3) + "</color>";
				if (!VersionUtils.ComicallyOldVersion.Equals(newestVersion) && version > newestVersion)
				{
					TextMeshProUGUI obj = this.version;
					((TMP_Text)obj).text = ((TMP_Text)obj).text + " <color=#888>[beta]</color>";
				}
			}
		}

		private static void DownloadNewestVersion(string url)
		{
			Process.Start(url);
		}

		private static bool R2ModmanIsRunning()
		{
			return Process.GetProcessesByName("r2modman").Length != 0;
		}
	}
	public class TerminalBrowserControlle