Decompiled source of Grey Announcer v1.0.1

GreyAnnouncer.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PluginConfig.API;
using PluginConfig.API.Decorators;
using PluginConfig.API.Fields;
using PluginConfig.API.Functionals;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GreyAnnouncer")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("My first plugin")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: AssemblyInformationalVersion("0.0.1")]
[assembly: AssemblyProduct("GreyAnnouncer")]
[assembly: AssemblyTitle("GreyAnnouncer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace greycsont.GreyAnnouncer
{
	public class Announcer
	{
		private enum ValidationState
		{
			Success,
			AudioFailedLoading,
			SharedCooldown,
			IndividualCooldown,
			DisabledByConfig,
			ClipNotFound,
			InvaildRankIndex
		}

		private static Dictionary<int, AudioClip> audioClips = new Dictionary<int, AudioClip>();

		public static List<ConfigEntry<bool>> EnabledStyleConfigs = new List<ConfigEntry<bool>>();

		private static readonly string[] rankAudioNames = new string[8] { "D", "C", "B", "A", "S", "SS", "SSS", "U" };

		private static float[] individualRankPlayCooldown = new float[8];

		private static float sharedRankPlayCooldown = 0f;

		private static readonly HashSet<string> audioFailedLoading = new HashSet<string>();

		private static AudioSource globalAudioSource;

		private static AudioSource localAudioSource;

		private static int limitOfRecursive = 0;

		public static void Initialize()
		{
			AddStyleConfigEntryToList();
			FindAvailableAudio(PathManager.GetGamePath(Path.Combine("ULTRAKILL_DATA", "Audio")));
		}

		public static void ReloadAudio()
		{
			Plugin.Log.LogInfo((object)"Reload audio...");
			FindAvailableAudio(PathManager.GetGamePath(Path.Combine("ULTRAKILL_DATA", "Audio")));
		}

		public static void AddAudioLowPassFilter()
		{
			if ((Object)(object)localAudioSource == (Object)null)
			{
				GetLocalAudioSource();
			}
			localAudioSource = AudioSourceManager.AddLowPassFilter(localAudioSource);
		}

		public static void RemoveAudioLowPassFilter()
		{
			if ((Object)(object)localAudioSource == (Object)null)
			{
				GetLocalAudioSource();
			}
			localAudioSource = AudioSourceManager.RemoveLowPassFilter(localAudioSource);
		}

		private static void GetLocalAudioSource()
		{
			if ((Object)(object)localAudioSource == (Object)null)
			{
				localAudioSource = GetGlobalAudioSource();
			}
			localAudioSource.spatialBlend = 0f;
			localAudioSource.priority = 0;
		}

		private static AudioSource GetGlobalAudioSource()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)globalAudioSource == (Object)null)
			{
				GameObject val = (GameObject)(((object)GameObject.Find("GlobalAudioPlayer")) ?? ((object)new GameObject("GlobalAudioPlayer")));
				globalAudioSource = val.GetComponent<AudioSource>() ?? val.AddComponent<AudioSource>();
				Object.DontDestroyOnLoad((Object)(object)val);
			}
			return globalAudioSource;
		}

		private static void FindAvailableAudio(string audioPath)
		{
			if (limitOfRecursive >= 2)
			{
				limitOfRecursive = 0;
				Plugin.Log.LogError((object)("Failed to find audio from \n New directory : " + PathManager.GetGamePath(Path.Combine("ULTRAKILL_DATA", "Audio")) + "\n Legacy directory : " + PathManager.GetCurrentPluginPath("audio")));
				return;
			}
			limitOfRecursive++;
			audioFailedLoading.Clear();
			TryToFindDirectoryOfAudioFolder(audioPath);
			TryToFetchAudios(audioPath);
			LoggingAudioFailedLoading();
			if (audioFailedLoading.SetEquals(rankAudioNames))
			{
				Plugin.Log.LogWarning((object)("No audio files found in the directory : " + audioPath + ". Start to search the legacy folder which is near the plugin/dll."));
				FindAvailableAudio(PathManager.GetCurrentPluginPath("audio"));
			}
		}

		private static void TryToFindDirectoryOfAudioFolder(string audioPath)
		{
			if (!Directory.Exists(audioPath))
			{
				Plugin.Log.LogWarning((object)("audio directory not found : " + audioPath));
				Directory.CreateDirectory(audioPath);
			}
		}

		private static void TryToFetchAudios(string audioPath)
		{
			string[] array = new string[5] { ".wav", ".mp3", ".ogg", ".aiff", ".aif" };
			for (int i = 0; i < rankAudioNames.Length; i++)
			{
				string path = null;
				string[] array2 = array;
				foreach (string text in array2)
				{
					string text2 = Path.Combine(audioPath, rankAudioNames[i] + text);
					if (File.Exists(text2))
					{
						path = text2;
						break;
					}
				}
				if (File.Exists(path))
				{
					((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(LoadAudioClip(path, i));
				}
				else
				{
					audioFailedLoading.Add(rankAudioNames[i]);
				}
			}
		}

		private static void LoggingAudioFailedLoading()
		{
			if (audioFailedLoading.Count == 0)
			{
				Plugin.Log.LogInfo((object)"All audios succeesfully loaded");
			}
			else
			{
				Plugin.Log.LogWarning((object)("Failed to load audio files: " + string.Join(", ", audioFailedLoading)));
			}
		}

		private static IEnumerator LoadAudioClip(string path, int key)
		{
			string url = new Uri(path).AbsoluteUri;
			AudioType audioType = GetAudioTypeFromExtension(url);
			Plugin.Log.LogInfo((object)("Loading audio : " + rankAudioNames[key] + " from " + url));
			UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, audioType);
			try
			{
				yield return www.SendWebRequest();
				if ((int)www.result != 1)
				{
					Plugin.Log.LogError((object)$"Failed to Load audio : {key}, Error message : {www.error}");
				}
				else
				{
					audioClips[key] = DownloadHandlerAudioClip.GetContent(www);
				}
			}
			finally
			{
				((IDisposable)www)?.Dispose();
			}
		}

		private static AudioType GetAudioTypeFromExtension(string path)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.GetExtension(path).ToLower();
			switch (text)
			{
			case ".wav":
				return (AudioType)20;
			case ".mp3":
				return (AudioType)13;
			case ".ogg":
				return (AudioType)14;
			case ".aiff":
			case ".aif":
				return (AudioType)2;
			default:
				Plugin.Log.LogWarning((object)("Unsupported audio format: " + text + ", defaulting to WAV"));
				return (AudioType)20;
			}
		}

		public static void PlaySound(int rank)
		{
			AudioClip val = CheckPlayValidation(rank);
			if (!((Object)(object)val == (Object)null))
			{
				if ((Object)(object)localAudioSource == (Object)null)
				{
					GetLocalAudioSource();
				}
				localAudioSource.clip = val;
				localAudioSource.volume = ((InstanceConfig.AudioSourceVolume.Value < 1f) ? InstanceConfig.AudioSourceVolume.Value : 1f);
				localAudioSource.Play();
				((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(CooldownCoroutine(delegate(float value)
				{
					sharedRankPlayCooldown = value;
				}, InstanceConfig.SharedRankPlayCooldown.Value));
				((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(CooldownCoroutine(delegate(float value)
				{
					individualRankPlayCooldown[rank] = value;
				}, InstanceConfig.IndividualRankPlayCooldown.Value));
			}
		}

		private static AudioClip CheckPlayValidation(int rank)
		{
			ValidationState playValidationState = GetPlayValidationState(rank);
			if (playValidationState != 0)
			{
				Plugin.Log.LogInfo((object)$"Skip {rankAudioNames[rank]} for {playValidationState}");
				return null;
			}
			AudioClip value;
			return audioClips.TryGetValue(rank, out value) ? value : null;
		}

		private static ValidationState GetPlayValidationState(int rank)
		{
			if (rank < 0 || rank > 7)
			{
				return ValidationState.InvaildRankIndex;
			}
			if (audioFailedLoading.Contains(rankAudioNames[rank]))
			{
				return ValidationState.AudioFailedLoading;
			}
			if (sharedRankPlayCooldown > 0f)
			{
				return ValidationState.SharedCooldown;
			}
			if (individualRankPlayCooldown[rank] > 0f)
			{
				return ValidationState.IndividualCooldown;
			}
			if (!EnabledStyleConfigs[rank].Value)
			{
				return ValidationState.DisabledByConfig;
			}
			if (!audioClips.TryGetValue(rank, out var _))
			{
				return ValidationState.ClipNotFound;
			}
			return ValidationState.Success;
		}

		public static void ResetTimerToZero()
		{
			sharedRankPlayCooldown = 0f;
			for (int i = 0; i < individualRankPlayCooldown.Length; i++)
			{
				individualRankPlayCooldown[i] = 0f;
			}
		}

		public static void UpdateAudioSourceVolume(float targetVolume, float duration = 0.35f)
		{
			((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(AudioSourceManager.FadeVolume(localAudioSource, targetVolume, duration));
		}

		private static IEnumerator CooldownCoroutine(Action<float> setCooldown, float initialCooldown)
		{
			if (initialCooldown <= 0f)
			{
				setCooldown(0f);
				yield break;
			}
			float cooldown = initialCooldown;
			float updateInterval = ((cooldown < 0.5f) ? (cooldown / 3f) : (cooldown / 10f));
			setCooldown(cooldown);
			while (cooldown > 0f)
			{
				yield return (object)new WaitForSeconds(updateInterval);
				cooldown = Math.Max(0f, cooldown - updateInterval);
				setCooldown(cooldown);
			}
		}

		private static void AddStyleConfigEntryToList()
		{
			EnabledStyleConfigs.Clear();
			EnabledStyleConfigs.Add(InstanceConfig.RankD_Enabled);
			EnabledStyleConfigs.Add(InstanceConfig.RankC_Enabled);
			EnabledStyleConfigs.Add(InstanceConfig.RankB_Enabled);
			EnabledStyleConfigs.Add(InstanceConfig.RankA_Enabled);
			EnabledStyleConfigs.Add(InstanceConfig.RankS_Enabled);
			EnabledStyleConfigs.Add(InstanceConfig.RankSS_Enabled);
			EnabledStyleConfigs.Add(InstanceConfig.RankSSS_Enabled);
			EnabledStyleConfigs.Add(InstanceConfig.RankU_Enabled);
		}
	}
	public class AudioSourceManager
	{
		public static AudioSource AddLowPassFilter(AudioSource audioSource)
		{
			if (!InstanceConfig.LowPassFilter_Enabled.Value)
			{
				return audioSource;
			}
			if ((Object)(object)audioSource == (Object)null)
			{
				return null;
			}
			AudioLowPassFilter val = ((Component)audioSource).gameObject.GetComponent<AudioLowPassFilter>() ?? ((Component)audioSource).gameObject.AddComponent<AudioLowPassFilter>();
			val.cutoffFrequency = 1000f;
			val.lowpassResonanceQ = 1f;
			return audioSource;
		}

		public static AudioSource RemoveLowPassFilter(AudioSource audioSource)
		{
			if ((Object)(object)audioSource == (Object)null)
			{
				return null;
			}
			AudioLowPassFilter component = ((Component)audioSource).GetComponent<AudioLowPassFilter>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			return audioSource;
		}

		public static IEnumerator FadeVolume(AudioSource audioSource, float targetVolume, float duration)
		{
			if (!((Object)(object)audioSource == (Object)null))
			{
				float startVolume = audioSource.volume;
				float timeStep = duration / 5f;
				float time = 0f;
				while (time < duration)
				{
					audioSource.volume = Mathf.Lerp(startVolume, targetVolume, time / duration);
					time += timeStep;
					yield return (object)new WaitForSeconds(timeStep);
				}
				audioSource.volume = targetVolume;
			}
		}
	}
	public class CoroutineRunner : MonoBehaviour
	{
		private static CoroutineRunner _instance;

		public static CoroutineRunner Instance
		{
			get
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Expected O, but got Unknown
				if ((Object)(object)_instance == (Object)null)
				{
					GameObject val = new GameObject("CoroutineRunner");
					_instance = val.AddComponent<CoroutineRunner>();
					Object.DontDestroyOnLoad((Object)(object)val);
				}
				return _instance;
			}
		}
	}
	public class PathManager
	{
		public static string GetCurrentPluginPath(string filePath)
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			return Path.Combine(directoryName, filePath);
		}

		public static string GetGamePath(string filePath)
		{
			string gameRootPath = Paths.GameRootPath;
			return Path.Combine(gameRootPath, filePath);
		}
	}
	public class ReflectionManager
	{
		public static void LoadByReflection(string assemblyName)
		{
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				Type type = executingAssembly.GetType(assemblyName);
				type.GetMethod("Initialize", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, null);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Failed to load optional module at: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(StyleHUD), "AscendRank")]
	public static class StyleHUDAscendRank_Patch
	{
		private static void Postfix(StyleHUD __instance)
		{
			Announcer.PlaySound(__instance.rankIndex);
		}
	}
	[HarmonyPatch(typeof(StyleHUD), "UpdateMeter")]
	public static class StyleHUDUpdateMeter_Patch
	{
		private static bool previousWasZero = true;

		private static void Postfix(StyleHUD __instance)
		{
			float currentMeter = GetCurrentMeter(__instance);
			bool flag = __instance.rankIndex == 0 && currentMeter > 0f;
			if (previousWasZero && flag)
			{
				Announcer.PlaySound(0);
			}
			previousWasZero = __instance.rankIndex == 0 && currentMeter <= 0f;
		}

		private static float GetCurrentMeter(StyleHUD instance)
		{
			return Traverse.Create((object)instance).Field("currentMeter").GetValue<float>();
		}
	}
	public class Water
	{
		public static bool isInWater;

		public static void CheckIsInWater(bool isSettingEnabled)
		{
			if (!isSettingEnabled)
			{
				Announcer.RemoveAudioLowPassFilter();
			}
			else if (isInWater)
			{
				Announcer.AddAudioLowPassFilter();
			}
		}
	}
	[HarmonyPatch(typeof(UnderwaterController), "EnterWater")]
	public static class AddLowPassFilters_Patch
	{
		public static void Postfix()
		{
			Water.isInWater = true;
			Announcer.AddAudioLowPassFilter();
		}
	}
	[HarmonyPatch(typeof(UnderwaterController), "OutWater")]
	public static class RemoveLowPassFilters_Patch
	{
		public static void Postfix()
		{
			Water.isInWater = false;
			Announcer.RemoveAudioLowPassFilter();
		}
	}
	public static class InstanceConfig
	{
		public const float DEFAULT_SHARED_RANK_COOLDOWN = 0f;

		public const float DEFAULT_INDIVIDUAL_RANK_COOLDOWN = 3f;

		public const bool DEFAULT_RANK_FILTER_ENABLED = true;

		public const float DEFAULT_AUDIO_SOURCE_VOLUME = 1f;

		public const bool DEFAULT_LOW_PASS_FILTER_ENABLED = true;

		public static ConfigEntry<float> SharedRankPlayCooldown;

		public static ConfigEntry<float> IndividualRankPlayCooldown;

		public static ConfigEntry<bool> RankD_Enabled;

		public static ConfigEntry<bool> RankC_Enabled;

		public static ConfigEntry<bool> RankB_Enabled;

		public static ConfigEntry<bool> RankA_Enabled;

		public static ConfigEntry<bool> RankS_Enabled;

		public static ConfigEntry<bool> RankSS_Enabled;

		public static ConfigEntry<bool> RankSSS_Enabled;

		public static ConfigEntry<bool> RankU_Enabled;

		public static ConfigEntry<float> AudioSourceVolume;

		public static ConfigEntry<bool> LowPassFilter_Enabled;

		public static void Initialize(Plugin plugin)
		{
			BindConfigEntryValues(plugin);
		}

		private static void BindConfigEntryValues(Plugin plugin)
		{
			BindCooldownConfigEntryValues(plugin);
			BindRankEnabledConfigEntryValues(plugin);
			BindAudioRelatedConfigEntryValues(plugin);
		}

		private static void BindCooldownConfigEntryValues(Plugin plugin)
		{
			SharedRankPlayCooldown = ((BaseUnityPlugin)plugin).Config.Bind<float>("Cooldown", "Shared_rank_play_cooldown", 0f, "Shared rank play cooldown(in secs)");
			IndividualRankPlayCooldown = ((BaseUnityPlugin)plugin).Config.Bind<float>("Cooldown", "Individual_rank_play_cooldown", 3f, "Individual rank play cooldown(in secs)");
		}

		private static void BindRankEnabledConfigEntryValues(Plugin plugin)
		{
			RankD_Enabled = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Enabled Style", "Destruction", true, "Set to true to allow announce at D-rank");
			RankC_Enabled = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Enabled Style", "Chaotic", true, "Set to true to allow announce at C-rank");
			RankB_Enabled = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Enabled Style", "Brutal", true, "Set to true to allow announce at B-rank");
			RankA_Enabled = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Enabled Style", "Anarchic", true, "Set to true to allow announce at A-rank");
			RankS_Enabled = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Enabled Style", "Supreme", true, "Set to true to allow announce at S-rank");
			RankSS_Enabled = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Enabled Style", "SSadistic", true, "Set to true to allow announce at SS-rank");
			RankSSS_Enabled = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Enabled Style", "SSShitstorm", true, "Set to true to allow announce at SSS-rank");
			RankU_Enabled = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Enabled Style", "ULTRAKILL", true, "Set to true to allow announce at U-rank");
		}

		private static void BindAudioRelatedConfigEntryValues(Plugin plugin)
		{
			AudioSourceVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio", "Audio_source_volume", 1f, "Volume of the Announcer ( Range : 0f ~ 1f )");
			LowPassFilter_Enabled = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Audio", "Under_water_low_pass_filter_Enabled", true, "Set to true to enable muffle effect when under water");
		}
	}
	[BepInPlugin("greycsont.ultrakill.GreyAnnouncer", "Grey Announcer", "1.0.1")]
	[BepInProcess("ULTRAKILL.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony harmony;

		internal static ManualLogSource Log;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			LoadMainModule();
			LoadOptionalModule();
			PatchHarmony();
			Log.LogInfo((object)"Plugin greycsont.ultrakill.GreyAnnouncer is loaded!");
		}

		private void LoadMainModule()
		{
			InstanceConfig.Initialize(this);
			Announcer.Initialize();
		}

		private void LoadOptionalModule()
		{
			CheckPluginLoaded("com.eternalUnion.pluginConfigurator", "greycsont.GreyAnnouncer.IPluginConfigurator");
		}

		private void PatchHarmony()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			harmony = new Harmony("greycsont.ultrakill.GreyAnnouncer.harmony");
			harmony.PatchAll();
		}

		public void CheckPluginLoaded(string GUID, string assemblyName)
		{
			if (!Chainloader.PluginInfos.ContainsKey(GUID))
			{
				Log.LogWarning((object)("Plugin " + GUID + " not loaded, stopping loading " + assemblyName));
			}
			else
			{
				ReflectionManager.LoadByReflection(assemblyName);
			}
		}
	}
	public class IPluginConfigurator
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static FloatValueChangeEventDelegate <>9__2_0;

			public static FloatValueChangeEventDelegate <>9__2_1;

			public static OnValueChangeEventDelegate <>9__2_2;

			public static Action<BoolValueChangeEvent> <>9__4_0;

			internal void <MainPanel>b__2_0(FloatValueChangeEvent e)
			{
				InstanceConfig.SharedRankPlayCooldown.Value = e.value;
				Announcer.ResetTimerToZero();
			}

			internal void <MainPanel>b__2_1(FloatValueChangeEvent e)
			{
				InstanceConfig.IndividualRankPlayCooldown.Value = e.value;
				Announcer.ResetTimerToZero();
			}

			internal void <MainPanel>b__2_2(FloatSliderValueChangeEvent e)
			{
				InstanceConfig.AudioSourceVolume.Value = e.newValue;
				Announcer.UpdateAudioSourceVolume(e.newValue);
			}

			internal void <AdvancedOptionPanel>b__4_0(BoolValueChangeEvent e)
			{
				Water.CheckIsInWater(e.value);
			}
		}

		private static PluginConfigurator config;

		public static void Initialize()
		{
			config = PluginConfigurator.Create("Grey Announcer", "greycsont.ultrakill.GreyAnnouncer");
			config.SetIconWithURL(PathManager.GetCurrentPluginPath("icon.png"));
			MainPanel();
		}

		private static void MainPanel()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Expected O, but got Unknown
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			ConfigHeader val = new ConfigHeader(config.rootPanel, "Main Settings", 24);
			val.textColor = new Color(0.85f, 0.85f, 0.85f, 1f);
			FloatField val2 = new FloatField(config.rootPanel, "Shared rank cooldown", "sharedRankPlayCooldown", InstanceConfig.SharedRankPlayCooldown.Value, 0f, 114514f);
			val2.defaultValue = 0f;
			object obj = <>c.<>9__2_0;
			if (obj == null)
			{
				FloatValueChangeEventDelegate val3 = delegate(FloatValueChangeEvent e)
				{
					InstanceConfig.SharedRankPlayCooldown.Value = e.value;
					Announcer.ResetTimerToZero();
				};
				<>c.<>9__2_0 = val3;
				obj = (object)val3;
			}
			val2.onValueChange += (FloatValueChangeEventDelegate)obj;
			FloatField val4 = new FloatField(config.rootPanel, "Individual rank cooldown", "individualRankPlaycooldown", InstanceConfig.IndividualRankPlayCooldown.Value, 0f, 1113f);
			val4.defaultValue = 3f;
			object obj2 = <>c.<>9__2_1;
			if (obj2 == null)
			{
				FloatValueChangeEventDelegate val5 = delegate(FloatValueChangeEvent e)
				{
					InstanceConfig.IndividualRankPlayCooldown.Value = e.value;
					Announcer.ResetTimerToZero();
				};
				<>c.<>9__2_1 = val5;
				obj2 = (object)val5;
			}
			val4.onValueChange += (FloatValueChangeEventDelegate)obj2;
			FloatSliderField val6 = new FloatSliderField(config.rootPanel, "Audio Volume", "Audio_Volume", Tuple.Create(0f, 1f), InstanceConfig.AudioSourceVolume.Value, 2);
			val6.defaultValue = 1f;
			object obj3 = <>c.<>9__2_2;
			if (obj3 == null)
			{
				OnValueChangeEventDelegate val7 = delegate(FloatSliderValueChangeEvent e)
				{
					InstanceConfig.AudioSourceVolume.Value = e.newValue;
					Announcer.UpdateAudioSourceVolume(e.newValue);
				};
				<>c.<>9__2_2 = val7;
				obj3 = (object)val7;
			}
			val6.onValueChange += (OnValueChangeEventDelegate)obj3;
			RankEnablePanel();
			AdvancedOptionPanel();
			ButtonField val8 = new ButtonField(config.rootPanel, "Reload Audio", "reload_audio");
			val8.onClick += new OnClick(Announcer.ReloadAudio);
		}

		private static void RankEnablePanel()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			ConfigPanel val = new ConfigPanel(config.rootPanel, "Rank Activation", "Rank_Activation");
			ConfigHeader val2 = new ConfigHeader(val, "Rank Activation", 24);
			val2.textColor = new Color(0.85f, 0.85f, 0.85f, 1f);
			BoolField val3 = BoolFieldFactory(val, "Destruction", "rank_D", InstanceConfig.RankD_Enabled, true);
			BoolField val4 = BoolFieldFactory(val, "Chaotic", "rank_C", InstanceConfig.RankC_Enabled, true);
			BoolField val5 = BoolFieldFactory(val, "Brutal", "rank_B", InstanceConfig.RankB_Enabled, true);
			BoolField val6 = BoolFieldFactory(val, "Anarchic", "rank_A", InstanceConfig.RankA_Enabled, true);
			BoolField val7 = BoolFieldFactory(val, "Supreme", "rank_S", InstanceConfig.RankS_Enabled, true);
			BoolField val8 = BoolFieldFactory(val, "SSadistic", "rank_SS", InstanceConfig.RankSS_Enabled, true);
			BoolField val9 = BoolFieldFactory(val, "SSShitstorm", "rank_SSS", InstanceConfig.RankSSS_Enabled, true);
			BoolField val10 = BoolFieldFactory(val, "ULTRAKILL", "rank_U", InstanceConfig.RankU_Enabled, true);
		}

		private static void AdvancedOptionPanel()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			ConfigPanel val = new ConfigPanel(config.rootPanel, "Advanced Option", "Advanced_Option");
			ConfigHeader val2 = new ConfigHeader(val, "Audio Frequency Filter", 24);
			val2.textColor = new Color(0.85f, 0.85f, 0.85f, 1f);
			BoolField val3 = BoolFieldFactory(val, "Filtering when under water", "LowPassFilter_Enabled", InstanceConfig.LowPassFilter_Enabled, true, delegate(BoolValueChangeEvent e)
			{
				Water.CheckIsInWater(e.value);
			});
		}

		private static BoolField BoolFieldFactory(ConfigPanel parentPanel, string name, string GUID, ConfigEntry<bool> configEntry, bool defaultValue = true, params Action<BoolValueChangeEvent>[] eventCallbacks)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			BoolField val = new BoolField(parentPanel, name, GUID, configEntry.Value);
			val.onValueChange += (BoolValueChangeEventDelegate)delegate(BoolValueChangeEvent e)
			{
				configEntry.Value = e.value;
				if (eventCallbacks != null)
				{
					Action<BoolValueChangeEvent>[] array = eventCallbacks;
					for (int i = 0; i < array.Length; i++)
					{
						array[i]?.Invoke(e);
					}
				}
			};
			val.defaultValue = defaultValue;
			return val;
		}
	}
	internal static class PluginDependencies
	{
		public const string PLUGINCONFIGURATOR_GUID = "com.eternalUnion.pluginConfigurator";
	}
	internal static class PluginInfo
	{
		public const string PLUGIN_GUID = "greycsont.ultrakill.GreyAnnouncer";

		public const string PLUGIN_NAME = "Grey Announcer";

		public const string PLUGIN_VERSION = "1.0.1";
	}
}