Decompiled source of Ultrakill Voiceline Mod v1.2.4

Plugins/UltrakillVoiceMod/UltrakillVoiceMod.dll

Decompiled 5 days 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.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using PluginConfig.API;
using PluginConfig.API.Decorators;
using PluginConfig.API.Fields;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("UltrakillVoiceMod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UltrakillVoiceMod")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("761705d4-f8d0-4609-9e66-ab9d62fdfdb3")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace UltrakillVoiceMod;

[BepInPlugin("com.NearRaindrop116.ultrakillvoicemod", "Ultrakill Voice Mod", "1.0.0")]
public class VoiceModPlugin : BaseUnityPlugin
{
	[CompilerGenerated]
	private sealed class <DelayedInitialize>d__8 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public VoiceModPlugin <>4__this;

		private string <pluginFolder>5__1;

		private string <soundsRoot>5__2;

		private string <defaultPath>5__3;

		private string <exclusiveRoot>5__4;

		private float <timeout>5__5;

		private float <timer>5__6;

		private string[] <>s__7;

		private int <>s__8;

		private string <file>5__9;

		private string[] <>s__10;

		private int <>s__11;

		private string <dir>5__12;

		private string <enemyKey>5__13;

		private string[] <>s__14;

		private int <>s__15;

		private string <file>5__16;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <DelayedInitialize>d__8(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<pluginFolder>5__1 = null;
			<soundsRoot>5__2 = null;
			<defaultPath>5__3 = null;
			<exclusiveRoot>5__4 = null;
			<>s__7 = null;
			<file>5__9 = null;
			<>s__10 = null;
			<dir>5__12 = null;
			<enemyKey>5__13 = null;
			<>s__14 = null;
			<file>5__16 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<pluginFolder>5__1 = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				<soundsRoot>5__2 = Path.Combine(<pluginFolder>5__1, "sounds");
				<defaultPath>5__3 = Path.Combine(<soundsRoot>5__2, "default");
				<exclusiveRoot>5__4 = Path.Combine(<soundsRoot>5__2, "exclusive");
				<timeout>5__5 = 15f;
				<timer>5__6 = 0f;
				break;
			case 1:
				<>1__state = -1;
				<timer>5__6 += Time.unscaledDeltaTime;
				break;
			}
			if (!Directory.Exists(<defaultPath>5__3) && !Directory.Exists(<exclusiveRoot>5__4))
			{
				if (<timer>5__6 >= <timeout>5__5)
				{
					((BaseUnityPlugin)<>4__this).Logger.LogError((object)"Timed out waiting for sound folders to appear.");
					return false;
				}
				<>2__current = null;
				<>1__state = 1;
				return true;
			}
			if (Directory.Exists(<defaultPath>5__3))
			{
				<>s__7 = Directory.GetFiles(<defaultPath>5__3, "*.wav");
				for (<>s__8 = 0; <>s__8 < <>s__7.Length; <>s__8++)
				{
					<file>5__9 = <>s__7[<>s__8];
					((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LoadClip(new WWW("file://" + <file>5__9), KillSounds));
					<file>5__9 = null;
				}
				<>s__7 = null;
			}
			else
			{
				((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)"No default folder found.");
			}
			if (Directory.Exists(<exclusiveRoot>5__4))
			{
				<>s__10 = Directory.GetDirectories(<exclusiveRoot>5__4);
				for (<>s__11 = 0; <>s__11 < <>s__10.Length; <>s__11++)
				{
					<dir>5__12 = <>s__10[<>s__11];
					<enemyKey>5__13 = Path.GetFileName(<dir>5__12).ToLower();
					ExclusiveKillSounds[<enemyKey>5__13] = new List<AudioClip>();
					<>s__14 = Directory.GetFiles(<dir>5__12, "*.wav");
					for (<>s__15 = 0; <>s__15 < <>s__14.Length; <>s__15++)
					{
						<file>5__16 = <>s__14[<>s__15];
						((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LoadClip(new WWW("file://" + <file>5__16), ExclusiveKillSounds[<enemyKey>5__13]));
						<file>5__16 = null;
					}
					<>s__14 = null;
					<enemyKey>5__13 = null;
					<dir>5__12 = null;
				}
				<>s__10 = null;
			}
			else
			{
				((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)"No exclusive folder found.");
			}
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <LoadClip>d__9 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public WWW www;

		public List<AudioClip> targetList;

		public VoiceModPlugin <>4__this;

		private AudioClip <clip>5__1;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <LoadClip>d__9(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<clip>5__1 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = www;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				<clip>5__1 = www.GetAudioClip(false, false);
				if ((Object)(object)<clip>5__1 != (Object)null)
				{
					targetList.Add(<clip>5__1);
				}
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	internal static ManualLogSource ModLogger;

	internal static AudioClip KillSound;

	internal static Dictionary<string, List<AudioClip>> ExclusiveKillSounds = new Dictionary<string, List<AudioClip>>();

	internal static List<AudioClip> KillSounds = new List<AudioClip>();

	private PluginConfigurator config;

	public static FloatField V1Volume;

	public static IntField V1Chance;

	private void Awake()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Expected O, but got Unknown
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Expected O, but got Unknown
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Expected O, but got Unknown
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Expected O, but got Unknown
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Expected O, but got Unknown
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Expected O, but got Unknown
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Expected O, but got Unknown
		ModLogger = ((BaseUnityPlugin)this).Logger;
		Harmony val = new Harmony("com.NearRaindrop116.ultrakillvoicemod");
		val.PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"VoiceModPlugin awake, patching...");
		config = PluginConfigurator.Create("Ultrakill Voiceline Mod", "com.NearRaindrop116.ultrakillvoicemod");
		config.SetIconWithURL("file://" + Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, "icon.png"));
		ConfigHeader val2 = new ConfigHeader(config.rootPanel, " ", 24);
		val2.textSize = 12;
		ConfigHeader val3 = new ConfigHeader(config.rootPanel, "--Ultrakill Voiceline Mod--", 24);
		ConfigHeader val4 = new ConfigHeader(config.rootPanel, " ", 24);
		val4.textSize = 12;
		ConfigHeader val5 = new ConfigHeader(config.rootPanel, "Volume at which voicelines are played. 0 - 1 including decimals", 24);
		val5.textSize = 12;
		V1Volume = new FloatField(config.rootPanel, "Voiceline Volume", "voice_volume", 1f);
		V1Volume.minimumValue = 0f;
		V1Volume.maximumValue = 1f;
		ConfigHeader val6 = new ConfigHeader(config.rootPanel, "Chance to play a voiceline. Ie: a value of 4 has a 1/4 chance to play", 24);
		val6.textSize = 12;
		V1Chance = new IntField(config.rootPanel, "Voiceline Chance", "voice_chance", 1);
		V1Chance.minimumValue = 1;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Current Volume is " + V1Volume.value));
		((MonoBehaviour)this).StartCoroutine(DelayedInitialize());
	}

	[IteratorStateMachine(typeof(<DelayedInitialize>d__8))]
	private IEnumerator DelayedInitialize()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <DelayedInitialize>d__8(0)
		{
			<>4__this = this
		};
	}

	[IteratorStateMachine(typeof(<LoadClip>d__9))]
	private IEnumerator LoadClip(WWW www, List<AudioClip> targetList)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <LoadClip>d__9(0)
		{
			<>4__this = this,
			www = www,
			targetList = targetList
		};
	}
}
[HarmonyPatch(typeof(EnemyIdentifier), "Death", new Type[] { typeof(bool) })]
public static class EnemyDeathPatch
{
	[CompilerGenerated]
	private sealed class <StopAndDestroyAfter>d__6 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public AudioSource source;

		public float delay;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <StopAndDestroyAfter>d__6(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(delay);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				source.Stop();
				Object.Destroy((Object)(object)((Component)source).gameObject);
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	private static float lastPlayTime = 0f;

	private static float cooldownSeconds = 1f;

	private static AudioSource currentKillAudio;

	private static float V1_Volume = VoiceModPlugin.V1Volume.value;

	private static int V1_Chance = VoiceModPlugin.V1Chance.value;

	public static void Prefix(EnemyIdentifier __instance, bool fromExplosion)
	{
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Expected O, but got Unknown
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		V1_Volume = VoiceModPlugin.V1Volume.value;
		V1_Chance = VoiceModPlugin.V1Chance.value;
		if ((Object)(object)__instance == (Object)null || __instance.dead)
		{
			return;
		}
		if (VoiceModPlugin.KillSounds == null || VoiceModPlugin.KillSounds.Count == 0)
		{
			VoiceModPlugin.ModLogger.LogWarning((object)"No kill sounds loaded.");
		}
		else
		{
			if (Random.Range(1, V1_Chance + 1) != 1)
			{
				return;
			}
			float time = Time.time;
			if (time < lastPlayTime + cooldownSeconds)
			{
				return;
			}
			if ((Object)(object)currentKillAudio != (Object)null)
			{
				currentKillAudio.Stop();
				Object.Destroy((Object)(object)((Component)currentKillAudio).gameObject);
				currentKillAudio = null;
			}
			lastPlayTime = time;
			try
			{
				Camera main = Camera.main;
				Transform val = ((main != null) ? ((Component)main).transform : null);
				if ((Object)(object)val == (Object)null)
				{
					VoiceModPlugin.ModLogger.LogWarning((object)"Could not find player camera to play sound.");
					return;
				}
				GameObject val2 = new GameObject("TempAudio");
				val2.transform.position = val.position;
				currentKillAudio = val2.AddComponent<AudioSource>();
				int index = Random.Range(0, VoiceModPlugin.KillSounds.Count);
				AudioClip val3 = VoiceModPlugin.KillSounds[index];
				string key = ((Object)__instance).name.ToLower().Replace("(clone)", "").Trim();
				AudioClip val4 = null;
				if (VoiceModPlugin.ExclusiveKillSounds.TryGetValue(key, out var value) && value.Count > 0 && Random.Range(0, VoiceModPlugin.KillSounds.Count + 1) == 0)
				{
					val4 = value[Random.Range(0, value.Count)];
				}
				else
				{
					if (VoiceModPlugin.KillSounds.Count <= 0)
					{
						VoiceModPlugin.ModLogger.LogWarning((object)"No kill sound available to play.");
						Object.Destroy((Object)(object)val2);
						return;
					}
					val4 = VoiceModPlugin.KillSounds[Random.Range(0, VoiceModPlugin.KillSounds.Count)];
				}
				VoiceModPlugin.ModLogger.LogInfo((object)("Current Volume is " + VoiceModPlugin.V1Volume.value));
				currentKillAudio.clip = val4;
				currentKillAudio.spatialBlend = 0f;
				currentKillAudio.volume = V1_Volume;
				currentKillAudio.loop = false;
				((Behaviour)currentKillAudio).enabled = true;
				currentKillAudio.Play();
				cooldownSeconds = val4.length + 0.1f;
				lastPlayTime = Time.time;
				StopAndDestroyAfter(currentKillAudio, val3.length + 0.1f);
				VoiceModPlugin.ModLogger.LogInfo((object)("Played sound: " + ((Object)val3).name + " for: " + ((Object)__instance).name + " at player position."));
			}
			catch (Exception arg)
			{
				VoiceModPlugin.ModLogger.LogError((object)$"Failed to play kill sound: {arg}");
			}
		}
	}

	[IteratorStateMachine(typeof(<StopAndDestroyAfter>d__6))]
	private static IEnumerator StopAndDestroyAfter(AudioSource source, float delay)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <StopAndDestroyAfter>d__6(0)
		{
			source = source,
			delay = delay
		};
	}
}