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();
}
}
}