using System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.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 TabsCrashLog { internal static class CrashLogWriter { [CompilerGenerated] private static class <>O { public static LogCallback <0>__OnLogMessage; public static UnhandledExceptionEventHandler <1>__OnUnhandledException; } private const string Divider = "──────────────────────────────────────────────"; private const string FatalDivider = "══════════════════════════════════════════════"; private static readonly object Lock = new object(); private static readonly Regex StackFrameRegex = new Regex("^\\s*at\\s+(.+?)(?:\\s+\\[|$)", RegexOptions.Compiled); private static string _path; private static bool _initialized; private static bool _headerWritten; private static string _lastReason; internal static string LogPath => _path; internal static void Initialize() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown if (!_initialized) { _initialized = true; _path = ResolveLogPath(); ResetLogFile(); object obj = <>O.<0>__OnLogMessage; if (obj == null) { LogCallback val = OnLogMessage; <>O.<0>__OnLogMessage = val; obj = (object)val; } Application.logMessageReceived += (LogCallback)obj; AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; } } internal static void Shutdown() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown object obj = <>O.<0>__OnLogMessage; if (obj == null) { LogCallback val = OnLogMessage; <>O.<0>__OnLogMessage = val; obj = (object)val; } Application.logMessageReceived -= (LogCallback)obj; AppDomain.CurrentDomain.UnhandledException -= OnUnhandledException; } private static string ResolveLogPath() { try { string directoryName = Path.GetDirectoryName(Application.dataPath); if (!string.IsNullOrEmpty(directoryName)) { return Path.Combine(directoryName, "crash.log"); } } catch { } return Path.Combine(Paths.BepInExRootPath, "crash.log"); } private static void ResetLogFile() { lock (Lock) { try { File.WriteAllText(_path, $"=== TABS Crash Log — {DateTime.Now:yyyy-MM-dd HH:mm:ss} ===\n\n"); _headerWritten = true; } catch { _headerWritten = false; } } } private unsafe static void OnLogMessage(string message, string stackTrace, LogType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if ((int)type != 0 && (int)type != 4 && (int)type != 1) { return; } string arg = (((int)type == 4) ? "EXCEPTION" : ((object)(*(LogType*)(&type))/*cast due to .constrained prefix*/).ToString().ToUpperInvariant()); string text = message?.Trim() ?? string.Empty; if (string.IsNullOrEmpty(text)) { text = "(no message)"; } if (!(text == _lastReason) || !string.IsNullOrWhiteSpace(stackTrace)) { _lastReason = text; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("──────────────────────────────────────────────"); stringBuilder.AppendLine($"[{DateTime.Now:HH:mm:ss}] {arg}"); stringBuilder.AppendLine("REASON : " + text); string text2 = ExtractSource(stackTrace); if (!string.IsNullOrEmpty(text2)) { stringBuilder.AppendLine("SOURCE : " + text2); } AppendStackTrace(stringBuilder, stackTrace); stringBuilder.AppendLine("──────────────────────────────────────────────"); Write(stringBuilder.ToString()); } } private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("══════════════════════════════════════════════"); stringBuilder.AppendLine($"[{DateTime.Now:HH:mm:ss}] *** FATAL UNHANDLED EXCEPTION ***"); if (e.ExceptionObject is Exception ex) { string text = (string.IsNullOrWhiteSpace(ex.Message) ? ex.GetType().Name : (ex.GetType().Name + " — " + ex.Message)); stringBuilder.AppendLine("REASON : " + text); if (!string.IsNullOrEmpty(ex.Source)) { stringBuilder.AppendLine("SOURCE : " + ex.Source); } stringBuilder.AppendLine(); stringBuilder.AppendLine(ex.ToString()); } else { stringBuilder.AppendLine($"REASON : {e.ExceptionObject}"); } stringBuilder.AppendLine("══════════════════════════════════════════════"); Write(stringBuilder.ToString()); } private static string ExtractSource(string stackTrace) { if (string.IsNullOrWhiteSpace(stackTrace)) { return null; } string[] array = stackTrace.Split(new char[1] { '\n' }); foreach (string input in array) { Match match = StackFrameRegex.Match(input); if (match.Success) { return match.Groups[1].Value.Trim(); } } return null; } private static void AppendStackTrace(StringBuilder sb, string stackTrace) { if (string.IsNullOrWhiteSpace(stackTrace)) { return; } sb.AppendLine(); string[] array = stackTrace.Split(new char[1] { '\n' }); for (int i = 0; i < array.Length; i++) { string text = array[i].TrimEnd(new char[1] { '\r' }); if (!string.IsNullOrWhiteSpace(text)) { sb.AppendLine(" " + text); } } } private static void Write(string block) { lock (Lock) { try { if (!_headerWritten) { File.AppendAllText(_path, $"=== TABS Crash Log — {DateTime.Now:yyyy-MM-dd HH:mm:ss} ===\n\n"); _headerWritten = true; } File.AppendAllText(_path, block); } catch { } } } } internal static class ModInfo { public const string Author = "Pretz"; public const string PluginGuid = "pretz.tabscrashlog"; public const string PluginName = "TABS Crash Log"; public const string Version = "1.0.1"; } [BepInPlugin("pretz.tabscrashlog", "TABS Crash Log", "1.0.1")] public class Plugin : BaseUnityPlugin { private void Awake() { CrashLogWriter.Initialize(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Crash log: " + CrashLogWriter.LogPath)); } private void OnDestroy() { CrashLogWriter.Shutdown(); } } }