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";
}
}