Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BM CustomSounds v0.2.0
BM_CustomSounds.dll
Decompiled 8 hours agousing 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)")); } } }