Please disclose if your mod was created primarily 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 UnityDebuggerAssistant v1.4.2
plugins/UnityDebuggerAssistant.dll
Decompiled 2 years agousing System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using MonoMod.Cil; using MonoMod.RuntimeDetour; using UnityDebuggerAssistant.Components; using UnityDebuggerAssistant.Filtering; using UnityDebuggerAssistant.Patches; using UnityDebuggerAssistant.Processing; using UnityDebuggerAssistant.Utils; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("LethalCompanyModding")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("A BepinEx plugin that captures Harmony and Monomod (wip) hook information at\r\n runtime to ease debugging")] [assembly: AssemblyFileVersion("1.4.2.0")] [assembly: AssemblyInformationalVersion("1.4.2+79a459d07838d68bc658c4def630236d2d21cdcd")] [assembly: AssemblyProduct("UnityDebuggerAssistant")] [assembly: AssemblyTitle("dev.mamallama.lcm.dbgasst")] [assembly: AssemblyMetadata("RepositoryUrl", "gitgithub.com:RobynLlama/UnityDebuggerAssistant.git")] [assembly: AssemblyVersion("1.4.2.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [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; } } } [BepInPlugin("dev.mamallama.lcm.dbgasst", "UnityDebuggerAssistant", "1.4.2")] public class UDAPlugin : BaseUnityPlugin { internal static ManualLogSource? Log; internal static PluginConfiguration UDASettings; private void Awake() { //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; UDASettings = new PluginConfiguration(((BaseUnityPlugin)this).Config); UDABlacklist.UpdateLists_Internal(); StringBuilder stringBuilder = new StringBuilder("\r\n\r\n>------------------------------------------------------------------------<\r\n Unity Debugger assistant is loaded and receiving exceptions!\r\n\r\n Note: That UDA will catch ALL exceptions, even harmless ones\r\n Please ONLY report logs to modders if you have an issue with their mod\r\n\r\n Config:\r\n"); stringBuilder.Append(" Using Per-Exception Whitelist: "); stringBuilder.AppendLine(UDASettings.EnableWhitelistPerException.Value.ToString()); stringBuilder.Append(" Using Per-Exception Blacklist: "); stringBuilder.AppendLine(UDASettings.EnableBlacklistPerException.Value.ToString()); stringBuilder.Append(" Using Per-Frame Whitelist: "); stringBuilder.AppendLine(UDASettings.EnableWhitelistPerFrame.Value.ToString()); stringBuilder.Append(" Using Per-Frame Blacklist: "); stringBuilder.AppendLine(UDASettings.EnableBlacklistPerFrame.Value.ToString()); stringBuilder.Append(" Total Filters: "); stringBuilder.AppendLine((UDABlacklist.ExceptionBlackList.Count() + UDABlacklist.FrameBlackList.Count()).ToString()); stringBuilder.AppendLine(">------------------------------------------------------------------------<"); Log.LogMessage((object)stringBuilder); ILHook.OnDetour = (Func<ILHook, MethodBase, Manipulator, bool>)Delegate.Combine(ILHook.OnDetour, new Func<ILHook, MethodBase, Manipulator, bool>(UDAPatchListener.ListenForPatch)); Harmony val = new Harmony("dev.mamallama.lcm.dbgasst"); val.PatchAll(typeof(ExceptionConstructorPatch)); GameObject val2 = new GameObject("UDAMain", new Type[2] { typeof(UDAExceptionBroker), typeof(UDAPostChainloadRunner) }) { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)val2); } } internal class PluginConfiguration { public readonly ConfigEntry<bool> EnableWhitelistPerException = Config.Bind<bool>(new ConfigDefinition("ExceptionFilter", "WhitelistEnabled"), true, new ConfigDescription("The per-exception whitelist filters out exceptions that do not originate from common game assemblies or BepinEx plugins.\nDisable this to catch everything. Will increase the log file size.", (AcceptableValueBase)null, Array.Empty<object>())); public readonly ConfigEntry<bool> EnableWhitelistPerFrame = Config.Bind<bool>(new ConfigDefinition("FrameFilter", "WhitelistEnabled"), false, new ConfigDescription("The per-frame whitelist will remove frames inside of exceptions that do not originate from common game assemblies.\nEnable this to reduce log file size by cutting out less relevant frames", (AcceptableValueBase)null, Array.Empty<object>())); public readonly ConfigEntry<bool> EnableBlacklistPerException = Config.Bind<bool>(new ConfigDefinition("ExceptionFilter", "BlacklistEnabled"), false, new ConfigDescription("The per-exception blacklist filters out exceptions that match the given patterns.\nThis is useful if you know a specific assembly throws errors you can ignore", (AcceptableValueBase)null, Array.Empty<object>())); public readonly ConfigEntry<bool> EnableBlacklistPerFrame = Config.Bind<bool>(new ConfigDefinition("FrameFilter", "BlacklistEnabled"), false, new ConfigDescription("The per-frame blacklist filters out exceptions that match the given patterns.\nThis is useful if you know a specific assembly throws errors you can ignore", (AcceptableValueBase)null, Array.Empty<object>())); public readonly ConfigEntry<string> ExceptionBlacklist = Config.Bind<string>(new ConfigDefinition("ExceptionFilter", "Blacklist"), "UniverseLib.Mono, UnityExplorer.", new ConfigDescription("A comma-separated list of assembly names to ignore in exception processing\nThis will be matched against the beginning of each assembly name so e.g. `UnityEngine.` will match all UnityEngine assemblies", (AcceptableValueBase)null, Array.Empty<object>())); public readonly ConfigEntry<string> FrameBlacklist = Config.Bind<string>(new ConfigDefinition("FrameFilter", "Blacklist"), "mscorlib", new ConfigDescription("A comma-separated list of assembly names to ignore in individual frame processing\nThis will be matched against the beginning of each assembly name so e.g. `UnityEngine.` will match all UnityEngine assemblies", (AcceptableValueBase)null, Array.Empty<object>())); public PluginConfiguration(ConfigFile Config) { }//IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0027: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0053: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_007f: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown //IL_00ab: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_00db: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown //IL_010b: Expected O, but got Unknown } internal static class LCMPluginInfo { public const string PLUGIN_GUID = "dev.mamallama.lcm.dbgasst"; public const string PLUGIN_NAME = "UnityDebuggerAssistant"; public const string PLUGIN_VERSION = "1.4.2"; } namespace UnityDebuggerAssistant.Utils { internal static class Helpers { internal static Assembly GetAssemblyByName(string name) { string name2 = name; return AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly assembly) => assembly.GetName().Name.Equals(name2, StringComparison.InvariantCultureIgnoreCase)); } } public static class UDAPatchListener { internal static bool ListenForPatch(ILHook hook, MethodBase @base, Manipulator manipulator) { if ((object)@base == null || manipulator == null || hook == null || ((Delegate)(object)manipulator).Target == null) { ManualLogSource? log = UDAPlugin.Log; if (log != null) { log.LogInfo((object)"Skipping a null/empty patch"); } return true; } UDAPatchStorage.AddPatchInformation(@base, ((Delegate)(object)manipulator).Target.GetType().Assembly); return true; } } internal static class UDAPatchStorage { private static readonly Dictionary<MethodBase, List<Assembly>> Patches = new Dictionary<MethodBase, List<Assembly>>(); private static readonly Assembly HarmonyAssembly = typeof(Harmony).Assembly; internal static bool AddPatchInformation(MethodBase method, Assembly assembly) { if ((object)assembly == null || assembly == HarmonyAssembly) { return false; } if (!Patches.TryGetValue(method, out List<Assembly> value)) { value = (Patches[method] = new List<Assembly>()); } if (value.Contains(assembly)) { return false; } value.Add(assembly); ManualLogSource? log = UDAPlugin.Log; if (log != null) { log.LogInfo((object)("blame " + assembly.GetName().Name + " for " + GeneralExtensions.FullDescription(method))); } return true; } internal static List<Assembly> GetPatchInformation(MethodBase method) { if (!Patches.TryGetValue(method, out List<Assembly> value)) { return new List<Assembly>(); } return value; } } public static class UDAPluginMarshal { internal static readonly Dictionary<Assembly, PluginInfo> InfoCache = new Dictionary<Assembly, PluginInfo>(); public static void Run() { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Dictionary<string, PluginInfo>.KeyCollection keys = Chainloader.PluginInfos.Keys; foreach (string item in keys) { Assembly assembly = ((object)Chainloader.PluginInfos[item].Instance).GetType().Assembly; PluginInfo val = Chainloader.PluginInfos[item]; if (val != null) { AddToInfoCache(assembly, val); } } stopwatch.Stop(); ManualLogSource? log = UDAPlugin.Log; if (log != null) { log.LogInfo((object)$"BepinEx Plugins Marshaled in {stopwatch.ElapsedMilliseconds}ms"); } } internal static bool AddToInfoCache(Assembly assembly, PluginInfo info) { if (InfoCache.ContainsKey(assembly)) { return false; } InfoCache.Add(assembly, info); return true; } } } namespace UnityDebuggerAssistant.Processing { public static class UDAExceptionHandler { public static void Handle(Exception ex) { int num = 0; MethodBase targetSite = ex.TargetSite; StackTrace stackTrace = new StackTrace(ex, fNeedFileInfo: true); Assembly assembly2 = targetSite?.DeclaringType.Assembly; bool flag = false; if ((object)assembly2 == null) { flag = true; _ = stackTrace.FrameCount; StackFrame[] frames = stackTrace.GetFrames(); foreach (StackFrame stackFrame in frames) { if (stackFrame.HasMethod()) { assembly2 = stackFrame.GetMethod().DeclaringType.Assembly; break; } } if ((object)assembly2 == null) { return; } } if (!UDAWhitelist.IsOnExceptionWhitelist(assembly2) || UDABlacklist.IsOnExceptionBlacklist(assembly2)) { return; } StringBuilder stringBuilder = new StringBuilder("\n\n--- Exception Handler ---\n\n"); stringBuilder.Append("Exception Caught: "); stringBuilder.AppendLine(ex.GetType().ToString()); stringBuilder.Append("Assembly: "); stringBuilder.Append(assembly2.GetName().Name); if (flag) { stringBuilder.Append(" (Guess)"); } stringBuilder.AppendLine(); if (UDAPluginMarshal.InfoCache.TryGetValue(assembly2, out PluginInfo value)) { WritePluginInfo(stringBuilder, value, 1); } stringBuilder.Append("Message: "); stringBuilder.AppendLine(ex.Message); if (ex.Source != null) { stringBuilder.Append("Source: "); stringBuilder.AppendLine(ex.Source); } stringBuilder.AppendLine(); stringBuilder.Append(Tabs(1)); stringBuilder.AppendLine("--- Begin Frames ---"); stringBuilder.AppendLine(); StackFrame[] frames2 = stackTrace.GetFrames(); foreach (StackFrame frame2 in frames2) { StringBuilder stringBuilder2 = new StringBuilder(); if (DumpFrame(stringBuilder2, frame2, 2)) { stringBuilder.Append(Tabs(1)); stringBuilder.Append("--FRAME "); num++; stringBuilder.Append(num); stringBuilder.AppendLine(":"); stringBuilder.Append(stringBuilder2.ToString()); } } stringBuilder.Append(Tabs(1)); stringBuilder.AppendLine("--- End Frames ---"); stringBuilder.AppendLine("\n--- End Exception Handler ---"); if (num > 0) { ManualLogSource? log = UDAPlugin.Log; if (log != null) { log.LogError((object)stringBuilder); } } static void DoHarmonyBlames(StringBuilder sb, ReadOnlyCollection<Patch>? Patches, int Indent) { if (Patches == null) { return; } foreach (Patch Patch in Patches) { DumpPatch(sb, Patch.PatchMethod.DeclaringType.Assembly, Indent); } } static bool DumpFrame(StringBuilder sb, StackFrame frame, int Indent) { MethodBase method = frame.GetMethod(); int iLOffset = frame.GetILOffset(); bool result = false; if ((object)method != null) { Assembly assembly3 = method.DeclaringType.Assembly; if (UDAWhitelist.IsOnFrameWhitelist(assembly3) && !UDABlacklist.IsOnFrameBlacklist(assembly3)) { result = true; sb.Append(Tabs(Indent)); sb.Append("In Assembly: "); sb.AppendLine(assembly3.GetName().Name); if (frame.GetFileName() != null) { sb.Append(Tabs(Indent)); sb.Append("Source: "); sb.Append(frame.GetFileName()); sb.Append(':'); sb.Append(frame.GetFileLineNumber()); sb.Append(','); sb.AppendLine(frame.GetFileColumnNumber().ToString()); } sb.Append(Tabs(Indent)); sb.Append("Target Method: "); sb.Append(method.DeclaringType.Name); sb.Append('.'); sb.AppendLine(method.Name); sb.AppendLine(); List<Assembly> patchInformation = UDAPatchStorage.GetPatchInformation(method); Patches patchInfo = Harmony.GetPatchInfo(method); if (patchInformation.Count > 0 || patchInfo != null) { sb.Append(Tabs(Indent)); sb.AppendLine("Patched By:"); } foreach (Assembly item in patchInformation) { DumpPatch(sb, item, Indent + 1); } if (patchInfo != null) { DoHarmonyBlames(sb, patchInfo.Prefixes, Indent + 1); DoHarmonyBlames(sb, patchInfo.Postfixes, Indent + 1); DoHarmonyBlames(sb, patchInfo.Finalizers, Indent + 1); } } } return result; } static void DumpPatch(StringBuilder sb, Assembly assembly, int Indent) { sb.Append(Tabs(Indent)); sb.AppendLine(assembly.GetName().Name); if (UDAPluginMarshal.InfoCache.TryGetValue(assembly, out PluginInfo value2)) { WritePluginInfo(sb, value2, Indent); } } static string GetPluginDirSandboxed(PluginInfo info) { int num2 = info.Location.IndexOf($"{Path.DirectorySeparatorChar}plugins{Path.DirectorySeparatorChar}"); if (num2 < 0) { return "Unknown"; } int length = info.Location.Length - num2; return new string(info.Location.ToCharArray(), num2, length); } static string Tabs(int n) { return new string(' ', n * 2); } static void WritePluginInfo(StringBuilder sb, PluginInfo info, int Indent) { sb.AppendLine(); sb.Append(Tabs(Indent)); sb.AppendLine("Plugin Info"); sb.Append(Tabs(Indent + 1)); sb.Append("GUID: "); sb.AppendLine(info.Metadata.GUID); sb.Append(Tabs(Indent + 1)); sb.Append("NAME/VER: "); sb.Append(info.Metadata.Name); sb.Append("@"); sb.AppendLine(info.Metadata.Version.ToString()); sb.Append(Tabs(Indent + 1)); sb.Append("LOCATION: "); sb.AppendLine(GetPluginDirSandboxed(info)); sb.AppendLine(); } } [MethodImpl(MethodImplOptions.NoInlining)] internal static void DebugThrow() { throw new Exception("Debug throw"); } } internal static class UDAExceptionProcessor { internal static readonly ConcurrentStack<Exception> Storage = new ConcurrentStack<Exception>(); internal static readonly int[] LastInExceptions = new int[10]; internal static int LastInPosition = 0; private static bool OperationUnderway = false; internal static void PushException(Exception ex) { int hashCode = ex.GetHashCode(); int[] lastInExceptions = LastInExceptions; foreach (int num in lastInExceptions) { if (hashCode == num) { return; } } LastInExceptions[LastInPosition] = hashCode; LastInPosition++; LastInPosition %= LastInExceptions.Length; Storage.Push(ex); } internal static void Run(Exception __instance) { if (OperationUnderway) { ManualLogSource? log = UDAPlugin.Log; if (log != null) { log.LogWarning((object)"Exception processor is busy"); } return; } OperationUnderway = true; try { UDAExceptionHandler.Handle(__instance); } catch (Exception ex) { ManualLogSource? log2 = UDAPlugin.Log; if (log2 != null) { log2.LogError((object)"The exception handler failed while running. Please report the next line to Robyn:"); } ManualLogSource? log3 = UDAPlugin.Log; if (log3 != null) { log3.LogError((object)ex); } } finally { OperationUnderway = false; } } } } namespace UnityDebuggerAssistant.Patches { public static class ExceptionStackGetterPatch { private static bool LockRoot; [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] internal static void ExceptionStackGot(Exception __instance) { if (!LockRoot) { LockRoot = true; UDAExceptionProcessor.Run(__instance); LockRoot = false; } } } [HarmonyPatch] public static class ExceptionConstructorPatch { private static IEnumerable<MethodBase> TargetMethods() { return typeof(Exception).GetConstructors(BindingFlags.Instance | BindingFlags.Public); } private static void Postfix(Exception __instance) { UDAExceptionProcessor.PushException(__instance); } } } namespace UnityDebuggerAssistant.Filtering { internal static class UDABlacklist { internal static string[] ExceptionBlackList = Array.Empty<string>(); internal static string[] FrameBlackList = Array.Empty<string>(); internal static bool IsOnExceptionBlacklist(Assembly assembly) { if (!UDAPlugin.UDASettings.EnableBlacklistPerException.Value) { return false; } return IsOnList_Internal(assembly.GetName().Name, in ExceptionBlackList); } internal static bool IsOnFrameBlacklist(Assembly assembly) { if (!UDAPlugin.UDASettings.EnableBlacklistPerException.Value) { return false; } return IsOnList_Internal(assembly.GetName().Name, in FrameBlackList); } internal static bool IsOnList_Internal(string name, in string[] blacklist) { string[] array = blacklist; foreach (string value in array) { if (name.StartsWith(value)) { return true; } } return false; } internal static void UpdateLists_Internal() { ExceptionBlackList = UDAPlugin.UDASettings.ExceptionBlacklist.Value.Split(new char[1] { ',' }); FrameBlackList = UDAPlugin.UDASettings.FrameBlacklist.Value.Split(new char[1] { ',' }); for (int i = 0; i < ExceptionBlackList.Length; i++) { ExceptionBlackList[i] = ExceptionBlackList[i].Trim(); } for (int j = 0; j < FrameBlackList.Length; j++) { FrameBlackList[j] = FrameBlackList[j].Trim(); } } } internal static class UDAWhitelist { internal static readonly List<Assembly> AssemblyWhiteList = new List<Assembly>(2) { Helpers.GetAssemblyByName("Assembly-CSharp"), Helpers.GetAssemblyByName("MMHOOK_Assembly-CSharp") }; internal static bool IsOnExceptionWhitelist(Assembly assembly) { return Whitelist(UDAPlugin.UDASettings.EnableWhitelistPerException.Value, assembly); } internal static bool IsOnFrameWhitelist(Assembly assembly) { return Whitelist(UDAPlugin.UDASettings.EnableWhitelistPerFrame.Value, assembly); } private static bool Whitelist(bool Setting, Assembly assembly) { if (UDAPluginMarshal.InfoCache.ContainsKey(assembly)) { return true; } if (Setting) { if (Setting) { return AssemblyWhiteList.Contains(assembly); } return false; } return true; } } } namespace UnityDebuggerAssistant.Components { public class UDAExceptionBroker : MonoBehaviour { private readonly Exception[] popped = new Exception[3]; private void Awake() { ManualLogSource? log = UDAPlugin.Log; if (log != null) { log.LogInfo((object)"UDAExceptionBroker active"); } } private void Update() { ConcurrentStack<Exception> storage = UDAExceptionProcessor.Storage; int num = storage.TryPopRange(popped); if (num > 0) { for (int i = 0; i < num; i++) { UDAExceptionProcessor.Run(popped[i]); } } } } public class UDAPostChainloadRunner : MonoBehaviour { private void Start() { ManualLogSource? log = UDAPlugin.Log; if (log != null) { log.LogInfo((object)"UDAPostChainloadRunner Starting"); } UDAPluginMarshal.Run(); } } }