/// <summary>
        /// Gets the log message for the specified stack trace.
        /// </summary>
        /// <param name="stackTrace">The stack trace, which must not be null.</param>
        /// <param name="cache">The cache of Harmony methods.</param>
        /// <param name="message">The location where the message will be stored.</param>
        internal static void GetStackTraceLog(StackTrace stackTrace, HarmonyMethodCache cache,
                                              StringBuilder message)
        {
            var          registry = ModDebugRegistry.Instance;
            ModDebugInfo mod;
            int          n = stackTrace.FrameCount;

            for (int i = 0; i < n; i++)
            {
                var frame  = stackTrace.GetFrame(i);
                var method = frame?.GetMethod();
                if (method == null)
                {
                    // Try to output as much as possible
                    method = cache.ParseInternalName(frame, message);
                }
                else
                {
                    method = DebugUtils.GetOriginalMethod(method);
                }
                if (method != null)
                {
                    // Try to give as much debug info as possible
                    int line = frame.GetFileLineNumber(), chr = frame.GetFileColumnNumber();
                    message.Append("  at ");
                    DebugUtils.AppendMethod(message, method);
                    if (line > 0 || chr > 0)
                    {
                        message.AppendFormat(" ({0:D}, {1:D})", line, chr);
                    }
                    else
                    {
                        message.AppendFormat(" [{0:D}]", frame.GetILOffset());
                    }
                    // The blame game
                    var type = method.DeclaringType;
                    var asm  = type.Assembly;
                    if (type.IsBaseGameType())
                    {
                        message.Append(" <Klei>");
                    }
                    else if (asm == typeof(string).Assembly)
                    {
                        message.Append(" <mscorlib>");
                    }
                    else if ((mod = registry.OwnerOfType(type)) != null)
                    {
                        message.Append(" <");
                        message.Append(mod.ModName ?? "unknown");
                        message.Append(">");
                    }
                    else if (asm.FullName.Contains("Unity"))
                    {
                        message.Append(" <Unity>");
                    }
                    message.AppendLine();
                    DebugUtils.GetPatchInfo(method, message);
                }
            }
        }
        /// <summary>
        /// Gets the log message for the specified exception.
        /// </summary>
        /// <param name="e">The exception, which must not be null.</param>
        /// <param name="cache">The cache of Harmony methods.</param>
        /// <returns>The log message for this exception.</returns>
        private static string GetExceptionLog(Exception e, HarmonyMethodCache cache)
        {
            // Better breakdown of the stack trace
            var message = new StringBuilder(8192);

            if (e is ReflectionTypeLoadException loadException)
            {
                message.AppendLine("Exception(s) when loading types:");
                foreach (var cause in loadException.LoaderExceptions)
                {
                    if (cause != null)
                    {
                        message.Append(GetExceptionLog(cause, cache));
                    }
                }
            }
            else
            {
                var stackTrace = new StackTrace(e);
                message.AppendFormat("{0}: {1}", e.GetType().Name, e.Message ??
                                     "<no message>");
                message.AppendLine();
                ModLoadHandler.CrashingMod = DebugUtils.GetFirstModOnCallStack(stackTrace);
                GetStackTraceLog(stackTrace, cache, message);
                // Log the root cause
                var cause = e.GetBaseException();
                if (cause != null && cause != e)
                {
                    message.AppendLine("Root cause exception:");
                    message.Append(GetExceptionLog(cause, cache));
                }
            }
            return(message.ToString());
        }