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 PaulMillerBug v1.1.1
PaulMillerBug/PaulMillerBug.dll
Decompiled 2 days 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.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PaulMillerBug")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: AssemblyProduct("PaulMillerBug")] [assembly: AssemblyTitle("PaulMillerBug")] [assembly: AssemblyVersion("1.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 PaulMillerBug { [BepInPlugin("com.kale.paulmillerbug", "Paul Miller Bug", "1.1.0")] [BepInProcess("Lethal Company.exe")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.kale.paulmillerbug"; public const string PluginName = "Paul Miller Bug"; public const string PluginVersion = "1.1.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> Volume; internal static readonly List<AudioClip> Clips = new List<AudioClip>(); internal static bool ClipsLoaded; private static readonly HashSet<int> AppliedBugs = new HashSet<int>(); private static Random rng = new Random(); private void Awake() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Paul Miller Bug sound replacement."); Volume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Volume", 1f, new ConfigDescription("Volume multiplier applied to the hoarding bug's voice AudioSources when clips are applied.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); new Harmony("com.kale.paulmillerbug").PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)string.Format("{0} v{1} loaded. Enabled={2} Volume={3}", "Paul Miller Bug", "1.1.0", Enabled.Value, Volume.Value)); GameObject val = new GameObject("PaulMillerBug_Loader"); Object.DontDestroyOnLoad((Object)val); ((MonoBehaviour)val.AddComponent<ClipLoader>()).StartCoroutine(LoadClips()); } internal static string PluginFolder() { try { string location = Assembly.GetExecutingAssembly().Location; if (!string.IsNullOrEmpty(location)) { return Path.GetDirectoryName(location); } } catch { } return Path.Combine(Paths.PluginPath, "PaulMillerBug"); } private IEnumerator LoadClips() { string text = PluginFolder(); Log.LogInfo((object)("Loading bug sounds from: " + text)); string[] array = new string[0]; try { array = Directory.GetFiles(text, "bug*.*"); } catch (Exception ex) { Log.LogError((object)("Could not list plugin folder: " + ex.Message)); } Array.Sort(array, (IComparer<string>?)StringComparer.OrdinalIgnoreCase); int attempted = 0; string[] array2 = array; foreach (string file in array2) { AudioType val; switch (Path.GetExtension(file).ToLowerInvariant()) { case ".wav": val = (AudioType)20; break; case ".mp3": val = (AudioType)13; break; case ".ogg": val = (AudioType)14; break; default: continue; } attempted++; string text2 = "file://" + file.Replace("\\", "/"); UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(text2, val); try { yield return req.SendWebRequest(); if (!string.IsNullOrEmpty(req.error)) { Log.LogError((object)("Failed to load " + Path.GetFileName(file) + ": " + req.error)); continue; } AudioClip content = DownloadHandlerAudioClip.GetContent(req); if ((Object)(object)content == (Object)null) { Log.LogError((object)("Loaded clip was null: " + file)); continue; } ((Object)content).name = Path.GetFileNameWithoutExtension(file); Clips.Add(content); Log.LogInfo((object)$"Loaded {((Object)content).name} ({content.length:F2}s, {content.frequency}Hz, ch={content.channels})"); } finally { ((IDisposable)req)?.Dispose(); } } ClipsLoaded = true; Log.LogInfo((object)$"Loaded {Clips.Count}/{attempted} bug clips."); LogGameVersion("after clip load"); if (Enabled.Value && Clips.Count > 0) { ApplyToAllBugs("clip-loading-complete"); } } internal static void ApplyToAllBugs(string reason) { int num = 0; try { HoarderBugAI[] array = Object.FindObjectsOfType<HoarderBugAI>(); for (int i = 0; i < array.Length; i++) { if (ApplyToBug(array[i])) { num++; } } array = Resources.FindObjectsOfTypeAll<HoarderBugAI>(); for (int i = 0; i < array.Length; i++) { if (ApplyToBug(array[i])) { num++; } } } catch (Exception arg) { Log.LogWarning((object)$"ApplyToAllBugs ({reason}) error: {arg}"); } Log.LogInfo((object)$"Applied Paul Miller Bug clips to {num} HoarderBugAI instance(s) ({reason}). Total clips={Clips.Count}"); } private static void SetField(object obj, string name, object value, List<string> ok) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown try { FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), name); if (fieldInfo == null) { Log.LogWarning((object)("HoarderBugAI." + name + " not found (game update?) - skipped")); return; } if (fieldInfo.FieldType.IsArray && !(value is Array)) { value = new AudioClip[1] { (AudioClip)value }; } else if (!fieldInfo.FieldType.IsArray && value is AudioClip[] array) { value = ((array.Length != 0) ? array[rng.Next(array.Length)] : null); } if (!fieldInfo.FieldType.IsAssignableFrom(value.GetType())) { Log.LogWarning((object)$"HoarderBugAI.{name} has type {fieldInfo.FieldType} - skipped"); return; } fieldInfo.SetValue(obj, value); ok.Add(name); } catch (Exception ex) { Log.LogWarning((object)("Setting " + name + " failed: " + ex.Message)); } } internal static void LogGameVersion(string when) { try { GameNetworkManager instance = GameNetworkManager.Instance; if ((Object)(object)instance != (Object)null) { Log.LogInfo((object)$"Game version ({when}): v{instance.gameVersionNum}"); } } catch (Exception ex) { Log.LogDebug((object)("Game version not readable yet: " + ex.Message)); } } internal static bool ApplyToBug(HoarderBugAI bug) { if ((Object)(object)bug == (Object)null || !Enabled.Value || Clips.Count == 0) { return false; } int instanceID; try { instanceID = ((Object)bug).GetInstanceID(); } catch { return false; } if (AppliedBugs.Contains(instanceID)) { return false; } try { AudioClip[] array = Clips.ToArray(); List<string> list = new List<string>(); SetField(bug, "chitterSFX", (AudioClip[])array.Clone(), list); SetField(bug, "angryScreechSFX", (AudioClip[])array.Clone(), list); SetField(bug, "angryVoiceSFX", Clips[rng.Next(Clips.Count)], list); SetField(bug, "hitPlayerSFX", Clips[rng.Next(Clips.Count)], list); try { if ((Object)(object)((EnemyAI)bug).creatureVoice != (Object)null) { ((EnemyAI)bug).creatureVoice.volume = Mathf.Clamp(((EnemyAI)bug).creatureVoice.volume * Volume.Value, 0f, 1f); } } catch { } try { if ((Object)(object)((EnemyAI)bug).creatureSFX != (Object)null) { ((EnemyAI)bug).creatureSFX.volume = Mathf.Clamp(((EnemyAI)bug).creatureSFX.volume * Volume.Value, 0f, 1f); } } catch { } AppliedBugs.Add(instanceID); Log.LogInfo((object)string.Format("Bug id={0}: replaced [{1}] with {2} clips. bugFlySFX left unchanged.", instanceID, string.Join(", ", list), array.Length)); return true; } catch (Exception arg) { Log.LogWarning((object)$"ApplyToBug failed for id={instanceID}: {arg}"); return false; } } } internal class ClipLoader : MonoBehaviour { } [HarmonyPatch(typeof(HoarderBugAI), "Start")] internal static class HoarderBugStartPatch { private static bool versionLogged; private static void Postfix(HoarderBugAI __instance) { if (!versionLogged) { versionLogged = true; Plugin.LogGameVersion("first bug spawn"); } if (Plugin.ClipsLoaded) { Plugin.ApplyToBug(__instance); } } } }