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 HornetAudioEditor v1.2.1
patchers/AudioTablePatcher.dll
Decompiled 7 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using Mono.Cecil; using Mono.Cecil.Cil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("0.0.0.0")] namespace HornetAudioEditor.Patcher; public class AudioTableOnEnablePatcher { public static IEnumerable<string> TargetDLLs => new string[1] { "Assembly-CSharp.dll" }; public static void Patch(AssemblyDefinition assembly) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) ModuleDefinition mainModule = assembly.MainModule; TypeDefinition type = mainModule.GetType("RandomAudioClipTable"); if (type != null && !((IEnumerable<MethodDefinition>)type.Methods).Any((MethodDefinition m) => ((MemberReference)m).Name == "OnEnable")) { MethodDefinition val = new MethodDefinition("OnEnable", (MethodAttributes)129, mainModule.ImportReference(typeof(void))); val.Body.GetILProcessor().Append(Instruction.Create(OpCodes.Ret)); type.Methods.Add(val); if (((IEnumerable<MethodDefinition>)type.Methods).Any((MethodDefinition m) => ((MemberReference)m).Name == "OnEnable")) { Console.WriteLine("AudioTablePatcher: Injected OnEnable into RandomAudioClipTable."); } } } }
plugins/HornetAudioEditor.dll
Decompiled 7 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; 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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("HornetAudioEditor")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.2.1.0")] [assembly: AssemblyInformationalVersion("1.2.1+910066f8bfcc92b17f3c026b4aff96fd4dd9f6fc")] [assembly: AssemblyProduct("HornetAudioEditor")] [assembly: AssemblyTitle("HornetAudioEditor")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace HornetAudioEditor { [BepInPlugin("alphalul.HornetAudioEditor", "Hornet Audio Editor", "1.2.1")] public class HornetAudioEditorPlugin : BaseUnityPlugin { private class AudioCollection { public HashSet<string> folders; public ProbabilityAudioClip[] vanillaClips; public bool includeVanillaClips; public AudioCollection(HashSet<string> folders, bool includeVanillaClips) { this.folders = folders; this.includeVanillaClips = includeVanillaClips; base..ctor(); } } [HarmonyPatch(typeof(RandomAudioClipTable), "OnEnable")] private class AudioTableOnEnable_Patch { [HarmonyPrefix] private static void OnEnable_Prefix(RandomAudioClipTable __instance) { Instance.LoadAudioTable(__instance); } } [HarmonyPatch(typeof(GameManager), "Start")] private class Start_Patch { [HarmonyPostfix] private static void Start_Postfix() { ((MonoBehaviour)Instance).StartCoroutine(Instance.RefreshAudioCollectionsRoutine()); } } [HarmonyPatch(typeof(RandomAudioClipTable), "CanPlay")] private class AudioLog_Patch { [HarmonyPostfix] private static void PlayAudio_Postfix(RandomAudioClipTable __instance, bool __result) { if (__result) { Instance.TryLogAudio(((Object)__instance).name); } } } private Dictionary<string, List<ProbabilityAudioClip>> folderClips; private Dictionary<string, AudioCollection> audioCollections; private string clipsPath; private string audioCollectionsPath; private string collectionPresetsPath; private static JsonSerializerSettings jsonSettings = new JsonSerializerSettings { Formatting = (Formatting)1, NullValueHandling = (NullValueHandling)1, DefaultValueHandling = (DefaultValueHandling)1 }; private Harmony harmony = new Harmony("alphalul.HornetAudioEditor"); private ConfigEntry<bool> configModEnabled; private ConfigEntry<bool> configRefreshOnSaveQuit; private ConfigEntry<bool> configLogAudio; private ConfigEntry<float> configLogSpamCooldown; private HashSet<string> recentLogs = new HashSet<string>(); private Queue<(string log, float time)> logBufferQueue = new Queue<(string, float)>(); public const string Id = "alphalul.HornetAudioEditor"; private static HornetAudioEditorPlugin Instance { get; set; } public static string Name => "Hornet Audio Editor"; public static string Version => "1.2.1"; private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } configModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Whether the mod is active. Set to false to disable modification of audio."); configRefreshOnSaveQuit = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RefreshOnSaveQuit", true, "Whether to reapply audioCollections.json upon returning to the title screen."); configLogAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("Logging", "LogAudio", true, "Whether to log the name of a RandomAudioClipTable when it plays a sound. Useful for finding table names."); configLogSpamCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Logging", "LogSpamCooldown", 0.2f, "How many seconds to wait until logging the same RandomAudioClipTable again. Helps reduce console spam."); if (configLogAudio.Value) { harmony.PatchAll(typeof(AudioLog_Patch)); } if (configModEnabled.Value) { clipsPath = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Clips"); audioCollectionsPath = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "audioCollections.json"); collectionPresetsPath = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Collection Presets"); Directory.CreateDirectory(clipsPath); harmony.PatchAll(typeof(AudioTableOnEnable_Patch)); if (configRefreshOnSaveQuit.Value) { harmony.PatchAll(typeof(Start_Patch)); } } } private IEnumerator RefreshAudioCollectionsRoutine() { RandomAudioClipTable[] loadedAudioTables = Resources.FindObjectsOfTypeAll<RandomAudioClipTable>(); ResetPersistentTables(loadedAudioTables); if (!RetrieveAudioCollectionsData()) { ((BaseUnityPlugin)this).Logger.LogError((object)"Something is wrong with 'audioCollections.json', unable to initialize HornetAudioEditor mod."); yield break; } foreach (string folder in folderClips.Keys) { List<AudioClip> streamedFolderClips = new List<AudioClip>(); string folderPath = Path.Combine(clipsPath, folder); if (!Directory.Exists(folderPath)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Folder " + folder + " doesn't exist")); continue; } string[] collectionWavFiles = Directory.GetFiles(folderPath, "*.wav", SearchOption.TopDirectoryOnly); string[] array = collectionWavFiles; foreach (string wavFile in array) { yield return WavToAudioClipRoutine(wavFile, streamedFolderClips); } foreach (AudioClip clip in streamedFolderClips) { List<ProbabilityAudioClip> list = folderClips[folder]; ProbabilityAudioClip val = new ProbabilityAudioClip { Clip = clip }; ((ProbabilityBase<AudioClip>)val).Probability = 1f; list.Add(val); } } RandomAudioClipTable[] array2 = loadedAudioTables; foreach (RandomAudioClipTable table in array2) { LoadAudioTable(table); } } private void ResetPersistentTables(RandomAudioClipTable[] loadedAudioTables) { if (audioCollections == null || folderClips == null) { return; } foreach (RandomAudioClipTable val in loadedAudioTables) { if (audioCollections.TryGetValue(((Object)val).name, out var value)) { val.clips = value.vanillaClips; } } } private IEnumerator WavToAudioClipRoutine(string wavFile, List<AudioClip> clips) { string uri = new Uri(wavFile).AbsoluteUri; UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(uri, (AudioType)20); try { yield return req.SendWebRequest(); AudioClip streamedClip = DownloadHandlerAudioClip.GetContent(req); ((Object)streamedClip).name = Path.GetFileNameWithoutExtension(wavFile); streamedClip.LoadAudioData(); clips.Add(streamedClip); } finally { ((IDisposable)req)?.Dispose(); } } private void LoadAudioTable(RandomAudioClipTable table) { if (audioCollections == null || folderClips == null || !audioCollections.TryGetValue(((Object)table).name, out var value)) { return; } value.vanillaClips = (ProbabilityAudioClip[])table.clips.Clone(); List<ProbabilityAudioClip> list = new List<ProbabilityAudioClip>(); foreach (string folder in value.folders) { list.AddRange(folderClips[folder]); } if (list.Count != 0) { if (value.includeVanillaClips) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Applied {list.Count} modded clip(s) and {table.clips.Length} vanilla clip(s) to {((Object)table).name}"); list.AddRange(table.clips); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Applied {list.Count} modded clip(s) to {((Object)table).name}"); } table.clips = list.ToArray(); } } private bool RetrieveAudioCollectionsData() { Dictionary<string, List<string>> dictionary; if (File.Exists(audioCollectionsPath)) { try { dictionary = JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(File.ReadAllText(audioCollectionsPath), jsonSettings); } catch (Exception ex) { Debug.LogError((object)("Hornet Audio Editor: " + ex.Message)); return false; } } else { dictionary = new Dictionary<string, List<string>> { [""] = new List<string>(3) { "Taunt Hornet Voice", "Taunt Seriously Hornet Voice", "Hornet_poshanka" } }; string contents = JsonConvert.SerializeObject((object)dictionary, jsonSettings); File.WriteAllText(audioCollectionsPath, contents); } ApplyCollectionPresets(dictionary); ParseRawAudioCollectionsData(dictionary); return true; } private void ApplyCollectionPresets(Dictionary<string, List<string>> rawAudioCollectionsData) { Dictionary<string, string[]> dictionary = new Dictionary<string, string[]>(); foreach (List<string> value2 in rawAudioCollectionsData.Values) { string[] array = value2.Where((string t) => t.EndsWith(".json")).ToArray(); foreach (string text in array) { try { bool flag = text.StartsWith('+'); string text2 = text.TrimStart('+'); if (!dictionary.TryGetValue(text2, out var value)) { value = (dictionary[text2] = JsonConvert.DeserializeObject<string[]>(File.ReadAllText(Path.Combine(collectionPresetsPath, text2)), jsonSettings)); } if (flag) { for (int j = 0; j < value.Length; j++) { if (!value[j].StartsWith('+')) { value[j] = "+" + value[j]; } } } value2.AddRange(value); } catch (Exception ex) { Debug.LogError((object)("Hornet Audio Editor: " + ex.Message)); } value2.Remove(text); } } } private void ParseRawAudioCollectionsData(Dictionary<string, List<string>> rawAudioCollectionsData) { folderClips = rawAudioCollectionsData.ToDictionary((KeyValuePair<string, List<string>> kvp) => kvp.Key, (KeyValuePair<string, List<string>> _) => new List<ProbabilityAudioClip>()); audioCollections = new Dictionary<string, AudioCollection>(); foreach (var (item, list2) in rawAudioCollectionsData) { foreach (string item2 in list2) { string key = item2.TrimStart('+'); if (audioCollections.TryGetValue(key, out var value)) { value.folders.Add(item); value.includeVanillaClips |= item2.StartsWith('+'); } else { audioCollections[key] = new AudioCollection(new HashSet<string> { item }, item2.StartsWith('+')); } } } } private void Update() { while (logBufferQueue.Count > 0 && Time.unscaledTime - logBufferQueue.Peek().time > configLogSpamCooldown.Value) { recentLogs.Remove(logBufferQueue.Dequeue().log); } } private void TryLogAudio(string log) { if (!recentLogs.Contains(log)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)log); recentLogs.Add(log); logBufferQueue.Enqueue((log, Time.unscaledTime)); } } } }