Decompiled source of Grey Announcer v0.1.5

GreyAnnouncer.dll

Decompiled 20 hours 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 HarmonyLib;
using Microsoft.CodeAnalysis;
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 static Dictionary<int, AudioClip> audioClips = new Dictionary<int, AudioClip>();

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

		private static float playCooldown = 0f;

		private static float cooldownDuration = 0.75f;

		private static List<string> audioFailedLoading = new List<string>();

		public static void Initialize()
		{
			string currentPluginPath = PathManager.GetCurrentPluginPath("audio");
			ConfiginiAnalyzer configiniAnalyzer = new ConfiginiAnalyzer("config.ini");
			cooldownDuration = configiniAnalyzer.GetCooldownDuration();
			DebugLogger.Log($"Cooldown: {cooldownDuration} seconds");
			audioFailedLoading.Clear();
			if (!Directory.Exists(currentPluginPath))
			{
				Debug.LogError((object)("audio directory not found: " + currentPluginPath));
				Directory.CreateDirectory(currentPluginPath);
				return;
			}
			for (int i = 0; i < audioNames.Length; i++)
			{
				string text = audioNames[i];
				string path = Path.Combine(currentPluginPath, text + ".wav");
				if (File.Exists(path))
				{
					((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(LoadAudioClip(path, i));
				}
				if (!File.Exists(path))
				{
					audioFailedLoading.Add(text);
				}
			}
			if (audioFailedLoading.Count == 0)
			{
				Debug.Log((object)"All audios succeesfully loaded");
			}
			if (audioFailedLoading.Count > 0)
			{
				Debug.LogWarning((object)("Failed to load audio files: " + string.Join(", ", audioFailedLoading)));
			}
		}

		private static IEnumerator LoadAudioClip(string path, int key)
		{
			string url = "file://" + path;
			UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, (AudioType)20);
			try
			{
				yield return www.SendWebRequest();
				if ((int)www.result != 1)
				{
					Debug.LogError((object)$"Failed to Load audio :{key},Error message :{www.error}");
					yield break;
				}
				AudioClip clip = DownloadHandlerAudioClip.GetContent(www);
				audioClips[key] = clip;
			}
			finally
			{
				((IDisposable)www)?.Dispose();
			}
		}

		private static IEnumerator CooldownTimer()
		{
			while (playCooldown > 0f)
			{
				playCooldown -= Time.deltaTime;
				yield return null;
			}
			playCooldown = 0f;
		}

		public static void PlaySound(int rank)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			AudioClip value;
			if (audioFailedLoading.Contains(audioNames[rank]))
			{
				DebugLogger.Log("Audio " + audioNames[rank] + " failed to load, skipping.");
			}
			else if (audioClips.TryGetValue(rank, out value))
			{
				if (!(playCooldown > 0f))
				{
					GameObject val = GameObject.Find("GlobalAudioPlayer");
					if ((Object)(object)val == (Object)null)
					{
						val = new GameObject("GlobalAudioPlayer");
						val.AddComponent<AudioSource>();
						Object.DontDestroyOnLoad((Object)(object)val);
					}
					AudioSource component = val.GetComponent<AudioSource>();
					component.clip = value;
					component.volume = 1f;
					component.spatialBlend = 0f;
					component.priority = 0;
					component.Play();
					DebugLogger.Log($"Play sound : {rank}");
					playCooldown = cooldownDuration;
					((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(CooldownTimer());
				}
			}
			else
			{
				DebugLogger.LogWarning($"audio not found : {rank}");
			}
		}
	}
	public class ConfiginiAnalyzer
	{
		private Dictionary<string, Dictionary<string, string>> configData;

		public ConfiginiAnalyzer(string fileName)
		{
			configData = LoadIniFile(PathManager.GetCurrentPluginPath(fileName));
		}

		public Dictionary<string, Dictionary<string, string>> LoadIniFile(string filePath)
		{
			Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>();
			string text = "";
			foreach (string item in File.ReadLines(filePath))
			{
				string text2 = item.Trim();
				if (text2.StartsWith(";") || string.IsNullOrWhiteSpace(text2))
				{
					continue;
				}
				if (text2.StartsWith("[") && text2.EndsWith("]"))
				{
					text = text2.Substring(1, text2.Length - 2);
					dictionary[text] = new Dictionary<string, string>();
				}
				else if (text2.Contains("="))
				{
					string[] array = text2.Split(new char[1] { '=' }, 2);
					string key = array[0].Trim();
					string value = array[1].Trim();
					if (!string.IsNullOrEmpty(text))
					{
						dictionary[text][key] = value;
					}
				}
			}
			return dictionary;
		}

		public float GetCooldownDuration()
		{
			if (TryGetConfigValue<float>("Timer", "cooldownDuration", out var result) && result >= 0f)
			{
				return result;
			}
			DebugLogger.Log("Invalid cooldown value in INI file. Returning default value.");
			return 0.75f;
		}

		private bool TryGetConfigValue<T>(string section, string key, out T result)
		{
			result = default(T);
			if (configData.ContainsKey(section) && configData[section].ContainsKey(key))
			{
				string value = configData[section][key];
				try
				{
					result = (T)Convert.ChangeType(value, typeof(T));
					return true;
				}
				catch (Exception ex)
				{
					DebugLogger.LogError("Failed to parse '" + key + "' in section [" + section + "]: " + ex.Message);
				}
			}
			return false;
		}
	}
	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 static class DebugLogger
	{
		private static bool isDebugEnabled = true;

		public static void Log(string message)
		{
			if (isDebugEnabled)
			{
				Debug.Log((object)(message ?? ""));
			}
		}

		public static void LogWarning(string message)
		{
			if (isDebugEnabled)
			{
				Debug.LogWarning((object)(message ?? ""));
			}
		}

		public static void LogError(string message)
		{
			if (isDebugEnabled)
			{
				Debug.LogError((object)(message ?? ""));
			}
		}
	}
	public class PathManager
	{
		public static string GetCurrentPluginPath(string filePath)
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			return Path.Combine(directoryName, filePath);
		}
	}
	[BepInPlugin("greycsont.ultrakill.Grey_Announcer", "Grey Announcer", "0.1.5")]
	[BepInProcess("ULTRAKILL.exe")]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony harmony;

		private void Awake()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Announcer.Initialize();
			harmony = new Harmony("greycsont.ultrakill.Grey_Announcer.harmony");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin greycsont.ultrakill.Grey_Announcer is loaded!");
		}
	}
	[HarmonyPatch(typeof(StyleHUD), "UpdateMeter")]
	public static class StyleHUDUpdateMeterPatch
	{
		private static bool previousWasZero = true;

		private static void Prefix(StyleHUD __instance)
		{
		}

		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>();
		}
	}
	[HarmonyPatch(typeof(StyleHUD), "AscendRank")]
	public static class StyleHUDAscendRankPatch
	{
		private static void Postfix(StyleHUD __instance)
		{
			Announcer.PlaySound(__instance.rankIndex);
		}
	}
	internal static class PluginInfo
	{
		public const string PLUGIN_GUID = "greycsont.ultrakill.Grey_Announcer";

		public const string PLUGIN_NAME = "Grey Announcer";

		public const string PLUGIN_VERSION = "0.1.5";
	}
}