Decompiled source of BM CustomSounds v0.2.0

BM_CustomSounds.dll

Decompiled 8 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.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
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: AssemblyTitle("BM_CustomSounds")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BM_CustomSounds")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e9cb9f1f-ebdc-4507-b444-1da2e74702d4")]
[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 BM_CustomSounds;

public static class AudioLoader
{
	private static ManualLogSource logger;

	private static bool loading;

	private static bool loaded;

	public static void Initialize(ManualLogSource log)
	{
		logger = log;
		loading = false;
		loaded = false;
	}

	public static IEnumerator LoadAllSounds(string directory, StartOfRound round)
	{
		if (loading)
		{
			yield break;
		}
		if (loaded)
		{
			ResetForRound(round);
			yield break;
		}
		loading = true;
		SoundRegistry.Clear();
		if (!Directory.Exists(directory))
		{
			Directory.CreateDirectory(directory);
			logger.LogInfo((object)("Created sound directory: " + directory));
			loading = false;
			loaded = true;
			yield break;
		}
		string[] files = Directory.GetFiles(directory, "*.*", SearchOption.AllDirectories);
		Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
		int supportedFiles = 0;
		int loadedFiles = 0;
		string[] array = files;
		foreach (string path in array)
		{
			AudioType audioType = GetAudioType(path);
			if ((int)audioType != 0)
			{
				supportedFiles++;
				AudioClip loadedClip = null;
				yield return LoadClip(path, audioType, delegate(AudioClip clip)
				{
					loadedClip = clip;
				});
				if (!((Object)(object)loadedClip == (Object)null))
				{
					string fileName = Path.GetFileNameWithoutExtension(path);
					string groupName = SoundRegistry.GetGroupName(fileName);
					((Object)loadedClip).name = fileName;
					SoundRegistry.RegisterClip(groupName, loadedClip);
					loadedFiles++;
				}
			}
		}
		loading = false;
		loaded = true;
		if (supportedFiles == 0)
		{
			logger.LogInfo((object)"No custom sounds found. Vanilla audio will be used.");
			yield break;
		}
		logger.LogWarning((object)"### BM_CUSTOMSOUNDS AUDIO READY ###");
		logger.LogInfo((object)("Loaded " + loadedFiles + "/" + supportedFiles + " custom audio file(s)."));
		SoundRegistry.LogSummary();
		ResetForRound(round);
	}

	private static void ResetForRound(StartOfRound round)
	{
		int num = 7319;
		if ((Object)(object)round != (Object)null)
		{
			num += round.randomMapSeed;
		}
		SoundRandomizer.Reset(num);
		SoundRegistry.ResetShuffleBags();
		logger.LogInfo((object)("Custom sound randomizer initialized. Seed=" + num));
	}

	private static IEnumerator LoadClip(string path, AudioType audioType, Action<AudioClip> callback)
	{
		//IL_000e: 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)
		string uri;
		try
		{
			uri = new Uri(path).AbsoluteUri;
		}
		catch (Exception ex)
		{
			Exception ex2 = ex;
			logger.LogError((object)("Invalid audio path: " + path + " | " + ex2.Message));
			callback(null);
			yield break;
		}
		UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(uri, audioType);
		try
		{
			yield return request.SendWebRequest();
			if ((int)request.result != 1)
			{
				logger.LogError((object)("Failed to load '" + Path.GetFileName(path) + "': " + request.error));
				callback(null);
				yield break;
			}
			AudioClip clip = DownloadHandlerAudioClip.GetContent(request);
			if ((Object)(object)clip == (Object)null)
			{
				logger.LogError((object)("AudioClip was null: " + path));
				callback(null);
				yield break;
			}
			callback(clip);
		}
		finally
		{
			((IDisposable)request)?.Dispose();
		}
	}

	private static AudioType GetAudioType(string path)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: 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_0046: 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)
		return (AudioType)(Path.GetExtension(path).ToLowerInvariant() switch
		{
			".ogg" => 14, 
			".wav" => 20, 
			".mp3" => 13, 
			_ => 0, 
		});
	}
}
public static class Patches
{
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	private static class StartOfRoundPatch
	{
		[HarmonyPostfix]
		private static void Postfix(StartOfRound __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				Plugin.Log.LogWarning((object)"### BM_CUSTOMSOUNDS STARTOFROUND HIT ###");
				((MonoBehaviour)__instance).StartCoroutine(AudioLoader.LoadAllSounds(Plugin.SoundDirectory, __instance));
			}
		}
	}

	[HarmonyPatch(typeof(AudioSource), "Play", new Type[] { })]
	private static class AudioSourcePlayPatch
	{
		[HarmonyPrefix]
		private static void Prefix(AudioSource __instance)
		{
			ReplaceSourceClip(__instance);
		}
	}

	[HarmonyPatch(typeof(AudioSource), "Play", new Type[] { typeof(ulong) })]
	private static class AudioSourcePlayUlongPatch
	{
		[HarmonyPrefix]
		private static void Prefix(AudioSource __instance)
		{
			ReplaceSourceClip(__instance);
		}
	}

	[HarmonyPatch(typeof(AudioSource), "Play", new Type[] { typeof(double) })]
	private static class AudioSourcePlayDoublePatch
	{
		[HarmonyPrefix]
		private static void Prefix(AudioSource __instance)
		{
			ReplaceSourceClip(__instance);
		}
	}

	[HarmonyPatch(typeof(AudioSource), "PlayDelayed", new Type[] { typeof(float) })]
	private static class AudioSourcePlayDelayedPatch
	{
		[HarmonyPrefix]
		private static void Prefix(AudioSource __instance)
		{
			ReplaceSourceClip(__instance);
		}
	}

	[HarmonyPatch(typeof(AudioSource), "PlayScheduled", new Type[] { typeof(double) })]
	private static class AudioSourcePlayScheduledPatch
	{
		[HarmonyPrefix]
		private static void Prefix(AudioSource __instance)
		{
			ReplaceSourceClip(__instance);
		}
	}

	[HarmonyPatch(typeof(AudioSource), "PlayOneShotHelper", new Type[]
	{
		typeof(AudioSource),
		typeof(AudioClip),
		typeof(float)
	})]
	private static class AudioSourcePlayOneShotHelperPatch
	{
		[HarmonyPrefix]
		private static void Prefix(AudioSource source, ref AudioClip clip, float volumeScale)
		{
			if (!((Object)(object)clip == (Object)null))
			{
				clip = SoundRegistry.GetReplacement(clip);
			}
		}
	}

	private static void ReplaceSourceClip(AudioSource source)
	{
		if (!((Object)(object)source == (Object)null) && !((Object)(object)source.clip == (Object)null))
		{
			AudioClip replacement = SoundRegistry.GetReplacement(source.clip);
			if (!((Object)(object)replacement == (Object)null) && !((Object)(object)replacement == (Object)(object)source.clip))
			{
				source.clip = replacement;
			}
		}
	}
}
[BepInPlugin("com.brox.BM_CustomSounds", "BM_CustomSounds", "0.2.0")]
public class Plugin : BaseUnityPlugin
{
	public const string ModGuid = "com.brox.BM_CustomSounds";

	public const string ModName = "BM_CustomSounds";

	public const string ModVersion = "0.2.0";

	internal static ManualLogSource Log;

	private static bool initialized;

	internal static string SoundDirectory => Path.Combine(Paths.PluginPath, "Brox-BM_CustomSounds", "sounds");

	private void Awake()
	{
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Expected O, but got Unknown
		if (!initialized)
		{
			initialized = true;
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"BM_CustomSounds v0.2.0 initializing...");
			SoundRegistry.Initialize(Log);
			AudioLoader.Initialize(Log);
			SoundRegistry.Clear();
			Harmony val = new Harmony("com.brox.BM_CustomSounds");
			val.PatchAll(typeof(Plugin).Assembly);
			Log.LogWarning((object)"### BM_CUSTOMSOUNDS HARMONY PATCHES INSTALLED ###");
			Log.LogInfo((object)"BM_CustomSounds loaded.");
		}
	}
}
public class SoundGroup
{
	private readonly List<AudioClip> clips = new List<AudioClip>();

	private readonly Queue<AudioClip> shuffleQueue = new Queue<AudioClip>();

	private AudioClip lastPlayed;

	public string Name { get; private set; }

	public int Count => clips.Count;

	public SoundGroup(string name)
	{
		Name = name;
	}

	public void AddClip(AudioClip clip)
	{
		if (!((Object)(object)clip == (Object)null))
		{
			clips.Add(clip);
		}
	}

	public AudioClip GetNextClip(Random random)
	{
		if (clips.Count == 0)
		{
			return null;
		}
		if (clips.Count == 1)
		{
			lastPlayed = clips[0];
			return clips[0];
		}
		if (shuffleQueue.Count == 0)
		{
			RebuildShuffleQueue(random);
		}
		return lastPlayed = shuffleQueue.Dequeue();
	}

	public void ResetShuffle(Random random)
	{
		shuffleQueue.Clear();
		lastPlayed = null;
		if (clips.Count > 1)
		{
			RebuildShuffleQueue(random);
		}
	}

	private void RebuildShuffleQueue(Random random)
	{
		List<AudioClip> list = new List<AudioClip>(clips);
		for (int num = list.Count - 1; num > 0; num--)
		{
			int index = random.Next(num + 1);
			AudioClip value = list[num];
			list[num] = list[index];
			list[index] = value;
		}
		if ((Object)(object)lastPlayed != (Object)null && list.Count > 1 && (Object)(object)list[0] == (Object)(object)lastPlayed)
		{
			int index2 = random.Next(1, list.Count);
			AudioClip value2 = list[0];
			list[0] = list[index2];
			list[index2] = value2;
		}
		foreach (AudioClip item in list)
		{
			shuffleQueue.Enqueue(item);
		}
	}
}
public static class SoundRandomizer
{
	private static Random random = new Random();

	public static Random Random => random;

	public static void Reset()
	{
		random = new Random();
	}

	public static void Reset(int seed)
	{
		random = new Random(seed);
	}
}
public static class SoundRegistry
{
	private static readonly Dictionary<string, SoundGroup> groups = new Dictionary<string, SoundGroup>(StringComparer.OrdinalIgnoreCase);

	private static readonly Dictionary<AudioClip, string> replacementGroups = new Dictionary<AudioClip, string>();

	private static ManualLogSource logger;

	private static readonly Regex VariantSuffix = new Regex("_(\\d+)$", RegexOptions.Compiled);

	public static int GroupCount => groups.Count;

	public static void Initialize(ManualLogSource log)
	{
		logger = log;
	}

	public static void Clear()
	{
		groups.Clear();
		replacementGroups.Clear();
	}

	public static string GetGroupName(string fileNameWithoutExtension)
	{
		if (string.IsNullOrEmpty(fileNameWithoutExtension))
		{
			return fileNameWithoutExtension;
		}
		Match match = VariantSuffix.Match(fileNameWithoutExtension);
		if (!match.Success)
		{
			return fileNameWithoutExtension;
		}
		return fileNameWithoutExtension.Substring(0, match.Index);
	}

	public static void RegisterClip(string groupName, AudioClip clip)
	{
		if (!string.IsNullOrEmpty(groupName) && !((Object)(object)clip == (Object)null))
		{
			if (!groups.TryGetValue(groupName, out var value))
			{
				value = new SoundGroup(groupName);
				groups[groupName] = value;
			}
			value.AddClip(clip);
			replacementGroups[clip] = groupName;
		}
	}

	public static bool HasReplacement(string originalClipName)
	{
		if (string.IsNullOrEmpty(originalClipName))
		{
			return false;
		}
		return groups.ContainsKey(originalClipName);
	}

	public static AudioClip GetReplacement(AudioClip original)
	{
		if ((Object)(object)original == (Object)null)
		{
			return null;
		}
		string key = ((Object)original).name;
		if (replacementGroups.TryGetValue(original, out var value))
		{
			key = value;
		}
		if (!groups.TryGetValue(key, out var value2))
		{
			return original;
		}
		AudioClip nextClip = value2.GetNextClip(SoundRandomizer.Random);
		if ((Object)(object)nextClip == (Object)null)
		{
			return original;
		}
		return nextClip;
	}

	public static void ResetShuffleBags()
	{
		foreach (KeyValuePair<string, SoundGroup> group in groups)
		{
			group.Value.ResetShuffle(SoundRandomizer.Random);
		}
		if (logger != null)
		{
			logger.LogInfo((object)"Sound shuffle bags reset.");
		}
	}

	public static void LogSummary()
	{
		if (logger == null)
		{
			return;
		}
		logger.LogInfo((object)("Loaded " + groups.Count + " custom sound group(s)."));
		foreach (KeyValuePair<string, SoundGroup> group in groups)
		{
			logger.LogInfo((object)("  " + group.Key + ": " + group.Value.Count + " variant(s)"));
		}
	}
}