Decompiled source of ErrorAnalyzer v1.3.0

ErrorAnalyzer.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ErrorAnalyzer")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.0.0")]
[module: UnverifiableCode]
namespace ErrorAnalyzer;

public class BepInExPluginIdentifier
{
	private readonly Dictionary<Assembly, List<PluginInfo>> pluginsByAssembly = new Dictionary<Assembly, List<PluginInfo>>();

	private readonly Dictionary<string, Assembly> assemblyByRootNamespace = new Dictionary<string, Assembly>();

	private readonly HashSet<string> duplicatedRootNamespace = new HashSet<string>();

	private readonly Dictionary<string, Assembly> assemblyByFullNamespace = new Dictionary<string, Assembly>();

	public BepInExPluginIdentifier()
	{
		foreach (PluginInfo value4 in Chainloader.PluginInfos.Values)
		{
			if ((Object)(object)value4.Instance == (Object)null)
			{
				continue;
			}
			Assembly assembly = ((object)value4.Instance).GetType().Assembly;
			if (pluginsByAssembly.TryGetValue(assembly, out var value))
			{
				value.Add(value4);
			}
			else
			{
				pluginsByAssembly.Add(assembly, new List<PluginInfo> { value4 });
			}
			string @namespace = ((object)value4.Instance).GetType().Namespace;
			if (string.IsNullOrEmpty(@namespace))
			{
				continue;
			}
			string text = @namespace.Split(new char[1] { '.' })[0];
			if (assemblyByFullNamespace.TryGetValue(@namespace, out var value2))
			{
				if (!(assembly != value2))
				{
				}
			}
			else
			{
				assemblyByFullNamespace.Add(@namespace, assembly);
			}
			if (duplicatedRootNamespace.Contains(text))
			{
				continue;
			}
			if (assemblyByRootNamespace.TryGetValue(text, out var value3))
			{
				if (!(value3 == assembly))
				{
					duplicatedRootNamespace.Add(text);
					assemblyByRootNamespace.Remove(text);
				}
			}
			else
			{
				assemblyByRootNamespace.Add(text, assembly);
			}
		}
	}

	public Assembly GetAssembly(string fullTypeName)
	{
		if (string.IsNullOrEmpty(fullTypeName))
		{
			return null;
		}
		int num = fullTypeName.LastIndexOf('.');
		if (num > 0)
		{
			string text = fullTypeName.Substring(0, num);
			if (assemblyByFullNamespace.TryGetValue(text, out var value))
			{
				return value;
			}
			string key = text;
			int num2 = text.IndexOf('.');
			if (num2 > 0)
			{
				key = text.Substring(0, num2);
			}
			if (assemblyByRootNamespace.TryGetValue(key, out var value2))
			{
				return value2;
			}
			return null;
		}
		return null;
	}

	public List<PluginInfo> GetPluginInfoList(Assembly assembly)
	{
		if (pluginsByAssembly.TryGetValue(assembly, out var value))
		{
			return value;
		}
		return new List<PluginInfo>();
	}

	public string DumpNamespaceMap()
	{
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("assembly by root namespace:");
		foreach (KeyValuePair<string, Assembly> item in assemblyByRootNamespace)
		{
			stringBuilder.AppendLine("[" + item.Key + "] " + item.Value.GetName().Name);
		}
		if (duplicatedRootNamespace.Count > 0)
		{
			stringBuilder.AppendLine("duplicate root namespace:");
			foreach (string item2 in duplicatedRootNamespace)
			{
				stringBuilder.AppendLine(item2);
			}
		}
		stringBuilder.AppendLine();
		stringBuilder.AppendLine("assembly by full namespace:");
		foreach (KeyValuePair<string, Assembly> item3 in assemblyByFullNamespace)
		{
			stringBuilder.AppendLine("[" + item3.Key + "]: " + item3.Value.GetName().Name);
		}
		return stringBuilder.ToString();
	}
}
public class HarmonyPatcherMapper
{
	private readonly Dictionary<string, List<MethodBase>> patchesByTargetType = new Dictionary<string, List<MethodBase>>();

	public HarmonyPatcherMapper()
	{
		foreach (MethodBase allPatchedMethod in PatchProcessor.GetAllPatchedMethods())
		{
			string fullName = allPatchedMethod.DeclaringType.FullName;
			if (!patchesByTargetType.TryGetValue(fullName, out var value))
			{
				value = new List<MethodBase>();
				patchesByTargetType[fullName] = value;
			}
			value.Add(allPatchedMethod);
		}
	}

	public bool IsTargetType(string typeName)
	{
		return patchesByTargetType.ContainsKey(typeName);
	}

	public MethodBase GetModMethod(string typeName, string methodName)
	{
		if (patchesByTargetType.TryGetValue(typeName, out var value))
		{
			foreach (MethodBase item in value)
			{
				if (item.Name == methodName)
				{
					return item;
				}
			}
		}
		return null;
	}

	public HashSet<Assembly> GetModAssembliesFromMethod(MethodBase targetMethod)
	{
		Patches patchInfo = Harmony.GetPatchInfo(targetMethod);
		if (patchInfo == null)
		{
			return new HashSet<Assembly>();
		}
		HashSet<Assembly> hashSet = new HashSet<Assembly>();
		foreach (Patch prefix in patchInfo.Prefixes)
		{
			hashSet.Add(prefix.PatchMethod.DeclaringType.Assembly);
		}
		foreach (Patch postfix in patchInfo.Postfixes)
		{
			hashSet.Add(postfix.PatchMethod.DeclaringType.Assembly);
		}
		foreach (Patch transpiler in patchInfo.Transpilers)
		{
			hashSet.Add(transpiler.PatchMethod.DeclaringType.Assembly);
		}
		return hashSet;
	}

	public HashSet<Assembly> GetModAssembliesFromType(string targetTypeName)
	{
		HashSet<Assembly> hashSet = new HashSet<Assembly>();
		if (!patchesByTargetType.TryGetValue(targetTypeName, out var value))
		{
			return hashSet;
		}
		foreach (MethodBase item in value)
		{
			hashSet.UnionWith(GetModAssembliesFromMethod(item));
		}
		return hashSet;
	}

	public string GetPatchesDescription(MethodBase targetMethod)
	{
		Patches patchInfo = PatchProcessor.GetPatchInfo(targetMethod);
		if (patchInfo == null)
		{
			return "";
		}
		StringBuilder stringBuilder = new StringBuilder();
		PatchesToString(stringBuilder, patchInfo.Prefixes, "; " + targetMethod.Name + "(Prefix)");
		PatchesToString(stringBuilder, patchInfo.Postfixes, "; " + targetMethod.Name + "(Postfix)");
		PatchesToString(stringBuilder, patchInfo.Transpilers, "; " + targetMethod.Name + "(Transpiler)");
		return stringBuilder.ToString();
	}

	public string DumpPatchMap()
	{
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append("DumpPatchMap type count: ").Append(patchesByTargetType.Keys.Count).AppendLine();
		foreach (KeyValuePair<string, List<MethodBase>> item in patchesByTargetType)
		{
			stringBuilder.Append("\n[Type: ").Append(item.Key).AppendLine("]");
			foreach (MethodBase item2 in item.Value)
			{
				stringBuilder.Append("-- ").Append(item.Key).Append(".")
					.Append(item2.Name)
					.AppendLine(" --");
				Patches patchInfo = PatchProcessor.GetPatchInfo(item2);
				PatchesToString(stringBuilder, patchInfo.Prefixes, "; (Prefix)");
				PatchesToString(stringBuilder, patchInfo.Postfixes, "; (Postfix)");
				PatchesToString(stringBuilder, patchInfo.Transpilers, "; (Transpiler)");
			}
		}
		return stringBuilder.ToString();
	}

	private void PatchesToString(StringBuilder sb, ReadOnlyCollection<Patch> patches, string textPostfix)
	{
		foreach (Patch patch in patches)
		{
			sb.Append(GeneralExtensions.FullDescription((MethodBase)patch.PatchMethod).Replace("System.Collections.Generic.IEnumerable<HarmonyLib.CodeInstruction>", "var").Replace("System.Reflection.Emit.ILGenerator", "var"));
			sb.Replace("static ", "");
			sb.AppendLine(textPostfix);
		}
	}
}
public static class StackParser
{
	private static readonly List<(string, string)> replaceTable = new List<(string, string)>
	{
		("System.Void ", "void "),
		("System.Boolean ", "bool "),
		("System.Byte ", "byte "),
		("System.Char ", "char "),
		("System.Decimal ", "decimal "),
		("System.Double ", "double "),
		("System.Single ", "float "),
		("System.Int32 ", "int "),
		("System.Int64 ", "long "),
		("System.Object ", "object "),
		("System.SByte ", "sbyte "),
		("System.Int16 ", "short "),
		("System.String ", "string "),
		("System.UInt32 ", "uint "),
		("System.UInt64 ", "ulong "),
		("System.UInt16 ", "ushort "),
		("System.Collections.Generic.List`1[T]", "List<T>"),
		("System.Collections.Generic.Dictionary`2[TKey,TValue]", "Dictionary<TKey, TValue>")
	};

	public static List<(string, string)> ParseStackTraceLines(string source)
	{
		List<(string, string)> list = new List<(string, string)>();
		if (string.IsNullOrEmpty(source))
		{
			return list;
		}
		string[] array = source.Split('\n', '\r');
		foreach (string text in array)
		{
			int num = text.IndexOf('(');
			if (num != -1)
			{
				int num2 = text.LastIndexOf('.', num);
				if (num2 != -1 && num - num2 - 2 > 0)
				{
					string item = (text.StartsWith("  at ") ? text.Substring(5, num2 - 5) : text.Substring(0, num2));
					string item2 = text.Substring(num2 + 1, num - num2 - 2);
					list.Add((item, item2));
				}
			}
		}
		return list;
	}

	public static string CleanStacktrace(string source)
	{
		if (string.IsNullOrEmpty(source))
		{
			return source;
		}
		string[] array = source.Split('\n', '\r');
		StringBuilder stringBuilder = new StringBuilder();
		StringBuilder stringBuilder2 = new StringBuilder();
		bool flag = true;
		string[] array2 = array;
		foreach (string text in array2)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				continue;
			}
			if (text.IndexOf(')') == -1)
			{
				stringBuilder2.AppendLine(text);
				if (flag)
				{
					flag = false;
					stringBuilder2.AppendLine();
				}
				continue;
			}
			stringBuilder.Clear();
			stringBuilder.Append(text);
			int num = text.LastIndexOf(" <", StringComparison.Ordinal);
			int num2 = text.LastIndexOf(">:", StringComparison.Ordinal);
			if (num != -1 && num2 > num)
			{
				stringBuilder.Remove(num, num2 - num + 2);
			}
			stringBuilder.Replace(" (at", "; (");
			stringBuilder.Replace(" inIL_", " ;IL_");
			foreach (var item in replaceTable)
			{
				stringBuilder.Replace(item.Item1, item.Item2);
			}
			stringBuilder2.AppendLine(stringBuilder.ToString());
		}
		return stringBuilder2.ToString();
	}
}
[BepInPlugin("aaa.dsp.plugin.ErrorAnalyzer", "ErrorAnalyzer", "1.3.0")]
public class Plugin : BaseUnityPlugin
{
	public const string GUID = "aaa.dsp.plugin.ErrorAnalyzer";

	public const string NAME = "ErrorAnalyzer";

	public const string VERSION = "1.3.0";

	public static ManualLogSource Log;

	public static bool isRegisitered;

	public static string errorString;

	public static string errorStackTrace;

	private static Harmony harmony;

	private static bool init;

	public static ConfigEntry<bool> ShowFullstack { get; private set; }

	public void Awake()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		harmony = new Harmony("aaa.dsp.plugin.ErrorAnalyzer");
		bool value = ((BaseUnityPlugin)this).Config.Bind<bool>("DEBUG Mode", "Enable", false, "Enable DEBUG mode to track the entity when starting up the game").Value;
		ShowFullstack = ((BaseUnityPlugin)this).Config.Bind<bool>("Message", "Show All Patches", false, "Show all mod patches on the stacktrace (By default it will not list GameData.Gametick() and below methods)");
		bool value2 = ((BaseUnityPlugin)this).Config.Bind<bool>("Message", "Dump All Patches", false, "Dump Harmony patches of all mods when the game load in BepInEx\\LogOutput.log").Value;
		if (Chainloader.PluginInfos.ContainsKey("dsp.nebula-multiplayer"))
		{
			Log.LogInfo((object)"Skip patching UIFatalErrorTip_Patch for Nebula is enabled");
		}
		else
		{
			try
			{
				harmony.PatchAll(typeof(UIFatalErrorTip_Patch));
				Application.logMessageReceived += new LogCallback(HandleLog);
				isRegisitered = true;
			}
			catch (Exception ex)
			{
				Log.LogError((object)"Error when patching UIFatalErrorTip_Patch");
				Log.LogError((object)ex);
			}
		}
		try
		{
			harmony.PatchAll(typeof(UIErrorEnhancer));
		}
		catch (Exception ex2)
		{
			Log.LogError((object)"Error when patching StacktraceParser");
			Log.LogError((object)ex2);
		}
		if (value)
		{
			TrackEntity_Patch.Enable(on: true);
		}
		if (value2)
		{
			harmony.PatchAll(typeof(Plugin));
		}
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	[HarmonyPatch(typeof(GameMain), "Begin")]
	private static void OnBegin()
	{
		if (!init)
		{
			init = true;
			HarmonyPatcherMapper harmonyPatcherMapper = new HarmonyPatcherMapper();
			Log.LogInfo((object)harmonyPatcherMapper.DumpPatchMap());
		}
	}

	public static void HandleLog(string logString, string stackTrace, LogType type)
	{
		if (string.IsNullOrEmpty(errorString) && logString.IndexOf("Exception") > 0)
		{
			errorString = logString;
			errorStackTrace = stackTrace;
			Log.LogDebug((object)"Exception Record");
		}
	}
}
internal class TrackEntity_Patch
{
	private static Harmony _patch;

	public static bool Active => _patch != null;

	public static int AstroId { get; private set; }

	public static int EntityId { get; private set; }

	public static Vector3 LocalPos { get; private set; }

	public static void Enable(bool on)
	{
		AstroId = 0;
		EntityId = 0;
		if (on)
		{
			if (_patch == null)
			{
				_patch = Harmony.CreateAndPatchAll(typeof(TrackEntity_Patch), (string)null);
			}
			Plugin.Log.LogInfo((object)"TrackEntity_Patch enable");
			return;
		}
		Harmony patch = _patch;
		if (patch != null)
		{
			patch.UnpatchSelf();
		}
		_patch = null;
		Plugin.Log.LogInfo((object)"TrackEntity_Patch disable");
	}

	public static void ResetId()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		AstroId = 0;
		EntityId = 0;
		LocalPos = Vector3.zero;
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(UIEntityBriefInfo), "_OnOpen")]
	private static void UIEntityBriefInfo_OnOpen(UIEntityBriefInfo __instance)
	{
		__instance.entityIdText.text = __instance.entityId.ToString();
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(FactorySystem), "GameTick", new Type[]
	{
		typeof(long),
		typeof(bool),
		typeof(int),
		typeof(int),
		typeof(int)
	})]
	[HarmonyPatch(typeof(FactorySystem), "GameTickLabProduceMode", new Type[]
	{
		typeof(long),
		typeof(bool),
		typeof(int),
		typeof(int),
		typeof(int)
	})]
	[HarmonyPatch(typeof(FactorySystem), "GameTickLabResearchMode", new Type[]
	{
		typeof(long),
		typeof(bool)
	})]
	[HarmonyPatch(typeof(FactorySystem), "GameTickInserters", new Type[]
	{
		typeof(long),
		typeof(bool),
		typeof(int),
		typeof(int)
	})]
	[HarmonyPatch(typeof(PowerSystem), "GameTick")]
	[HarmonyPatch(typeof(CargoTraffic), "SpraycoaterGameTick")]
	[HarmonyPatch(typeof(CargoTraffic), "PresentCargoPathsAsync")]
	[HarmonyPatch(typeof(DefenseSystem), "GameTick")]
	[HarmonyPatch(typeof(ConstructionSystem), "GameTick")]
	private static Exception GetFactoryId(Exception __exception, PlanetFactory ___factory)
	{
		if (__exception != null && AstroId == 0)
		{
			AstroId = ___factory.planet.astroId;
		}
		return __exception;
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(MinerComponent), "InternalUpdate")]
	[HarmonyPatch(typeof(AssemblerComponent), "InternalUpdate")]
	[HarmonyPatch(typeof(FractionatorComponent), "InternalUpdate")]
	[HarmonyPatch(typeof(FractionatorComponent), "InternalUpdate")]
	[HarmonyPatch(typeof(EjectorComponent), "InternalUpdate")]
	[HarmonyPatch(typeof(SiloComponent), "InternalUpdate")]
	[HarmonyPatch(typeof(LabComponent), "InternalUpdateAssemble")]
	[HarmonyPatch(typeof(LabComponent), "InternalUpdateResearch")]
	[HarmonyPatch(typeof(InserterComponent), "InternalOffsetCorrection")]
	[HarmonyPatch(typeof(SpraycoaterComponent), "InternalUpdate")]
	[HarmonyPatch(typeof(TurretComponent), "InternalUpdate")]
	private static Exception GetEntityId(Exception __exception, int ___entityId)
	{
		if (__exception != null && EntityId == 0)
		{
			EntityId = ___entityId;
		}
		return __exception;
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(InserterComponent), "InternalUpdate_Bidirectional")]
	[HarmonyPatch(typeof(InserterComponent), "InternalUpdate")]
	[HarmonyPatch(typeof(InserterComponent), "InternalUpdateNoAnim")]
	[HarmonyPatch(typeof(DispenserComponent), "InternalTick")]
	private static Exception GetInserterId(Exception __exception, int ___entityId, PlanetFactory factory)
	{
		if (__exception != null)
		{
			if (AstroId == 0)
			{
				AstroId = factory.planet.astroId;
			}
			if (EntityId == 0)
			{
				EntityId = ___entityId;
			}
		}
		return __exception;
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(StationComponent), "DetermineDispatch")]
	[HarmonyPatch(typeof(StationComponent), "InternalTickLocal")]
	[HarmonyPatch(typeof(StationComponent), "InternalTickRemote")]
	private static Exception GetStationId(Exception __exception, int ___entityId, int ___planetId)
	{
		if (__exception != null)
		{
			if (AstroId == 0)
			{
				AstroId = ___planetId;
			}
			if (EntityId == 0)
			{
				EntityId = ___entityId;
			}
		}
		return __exception;
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(CargoPath), "PresentCargos")]
	private static Exception GetCargoPathPos(Exception __exception, Vector3[] ___pointPos)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		if (__exception != null && LocalPos == Vector3.zero)
		{
			LocalPos = ___pointPos[0];
		}
		return __exception;
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(CargoTraffic), "SetBeltState")]
	private static Exception SetBeltState()
	{
		return null;
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(CargoContainer), "RemoveCargo")]
	private static Exception RemoveCargo()
	{
		return null;
	}

	[HarmonyFinalizer]
	[HarmonyPatch(typeof(CargoTraffic), "PickupBeltItems")]
	private static Exception PickupBeltItems()
	{
		return null;
	}
}
internal class UIErrorEnhancer
{
	private static bool isChecked;

	private static BepInExPluginIdentifier bepInExPluginIdentifier;

	private static HarmonyPatcherMapper harmonyPatcherMapper;

	[HarmonyPostfix]
	[HarmonyPatch(typeof(UIFatalErrorTip), "_OnClose")]
	public static void OnClose_Postfix()
	{
		isChecked = false;
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(UIFatalErrorTip), "_OnOpen")]
	public static void OnOpen_Postfix(UIFatalErrorTip __instance)
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		if (!isChecked)
		{
			string text = __instance.errorLogText.text;
			string text2 = ParseAndAnalysis(text, Plugin.ShowFullstack.Value);
			text = StackParser.CleanStacktrace(text);
			Plugin.Log.LogInfo((object)text2);
			__instance.errorLogText.text = text + text2;
			__instance.rectTrans.sizeDelta = new Vector2(__instance.rectTrans.sizeDelta.x, __instance.errorLogText.preferredHeight + 45f);
			((Graphic)__instance.errorLogText).rectTransform.sizeDelta = new Vector2(((Graphic)__instance.errorLogText).rectTransform.sizeDelta.x, __instance.errorLogText.preferredHeight + 2f);
			isChecked = true;
		}
	}

	public static string ParseAndAnalysis(string errorLog, bool showAllPatches = false)
	{
		if (harmonyPatcherMapper == null)
		{
			harmonyPatcherMapper = new HarmonyPatcherMapper();
		}
		if (bepInExPluginIdentifier == null)
		{
			bepInExPluginIdentifier = new BepInExPluginIdentifier();
		}
		string text = "";
		List<(string, string)> list = StackParser.ParseStackTraceLines(errorLog);
		if (list.Count == 0)
		{
			return text;
		}
		string text2 = "";
		HashSet<Assembly> hashSet = new HashSet<Assembly>();
		HashSet<Assembly> hashSet2 = new HashSet<Assembly>();
		string item = list[0].Item1;
		Assembly assembly = bepInExPluginIdentifier.GetAssembly(list[0].Item1);
		if (assembly != null)
		{
			hashSet.Add(assembly);
		}
		MethodBase modMethod = harmonyPatcherMapper.GetModMethod(list[0].Item1, list[0].Item2);
		if (modMethod != null)
		{
			hashSet.UnionWith(harmonyPatcherMapper.GetModAssembliesFromMethod(modMethod));
			text2 += harmonyPatcherMapper.GetPatchesDescription(modMethod);
		}
		if (hashSet.Count == 0)
		{
			hashSet2 = harmonyPatcherMapper.GetModAssembliesFromType(list[0].Item1);
		}
		bool flag = false;
		for (int i = 1; i < list.Count; i++)
		{
			string item2 = list[i].Item1;
			string item3 = list[i].Item2;
			Assembly assembly2 = bepInExPluginIdentifier.GetAssembly(item2);
			if (assembly2 != null)
			{
				hashSet.Add(assembly2);
			}
			if (!showAllPatches)
			{
				if (flag)
				{
					continue;
				}
				if (item2 == "VFPreload")
				{
					flag = true;
				}
				if (item2 == "GameMain")
				{
					flag = true;
				}
				if (item3 == "GameTick" && (item2 == "GameData" || item2 == "PlanetFactory"))
				{
					flag = true;
				}
				if (flag)
				{
					continue;
				}
			}
			MethodBase modMethod2 = harmonyPatcherMapper.GetModMethod(item2, item3);
			if (modMethod2 != null)
			{
				hashSet.UnionWith(harmonyPatcherMapper.GetModAssembliesFromMethod(modMethod2));
				text2 += harmonyPatcherMapper.GetPatchesDescription(modMethod2);
				flag = true;
			}
		}
		if (hashSet2.Count > 0)
		{
			text = text + "\n[== Mods to " + item + " ==]: ";
			foreach (Assembly item4 in hashSet2)
			{
				text = text + "[" + item4.GetName().Name + "]";
			}
		}
		if (hashSet.Count > 0)
		{
			text += "\n[== Mods on stack trace ==]: ";
			foreach (Assembly item5 in hashSet)
			{
				text = text + "[" + item5.GetName().Name + "]";
			}
			text = text + "\n" + text2;
		}
		UpdateExtarTitleString(hashSet);
		return text;
	}

	private static void UpdateExtarTitleString(HashSet<Assembly> relevantAssemblies)
	{
		UIFatalErrorTip_Patch.ExtarTitleString = ((relevantAssemblies.Count > 0) ? "possible candidates: " : "");
		foreach (Assembly relevantAssembly in relevantAssemblies)
		{
			foreach (PluginInfo pluginInfo in bepInExPluginIdentifier.GetPluginInfoList(relevantAssembly))
			{
				string name = pluginInfo.Metadata.Name;
				string text = pluginInfo.Metadata.Version.ToString();
				UIFatalErrorTip_Patch.ExtarTitleString = UIFatalErrorTip_Patch.ExtarTitleString + "[" + name + text + "]";
			}
		}
	}
}
[HarmonyPatch(typeof(UIFatalErrorTip))]
internal class UIFatalErrorTip_Patch
{
	private static UIButton btnClose;

	private static UIButton btnCopy;

	private static UIButton btnInspect;

	private static bool waitingToRefresh;

	private static int astroId;

	private static int entityId;

	private static Vector3 localPos;

	public static string ExtarTitleString { get; set; } = "";


	[HarmonyPostfix]
	[HarmonyPatch("_OnRegEvent")]
	private static void OnRegEvent_Postfix()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		if (!Plugin.isRegisitered)
		{
			return;
		}
		Plugin.isRegisitered = false;
		try
		{
			Application.logMessageReceived -= new LogCallback(Plugin.HandleLog);
			if (string.IsNullOrEmpty(Plugin.errorString))
			{
				return;
			}
			string[] array = Plugin.errorStackTrace.Split('\n', '\r');
			Plugin.Log.LogDebug((object)("Error captured during loading. Lines count: " + array.Length));
			if (array.Length > 15)
			{
				StringBuilder stringBuilder = new StringBuilder();
				for (int i = 0; i < 5; i++)
				{
					stringBuilder.AppendLine(array[i].TrimEnd('\n', '\r'));
				}
				stringBuilder.AppendLine($"...(skip the middle {array.Length - 15} lines)");
				for (int j = array.Length - 10; j < array.Length; j++)
				{
					stringBuilder.AppendLine(array[j].TrimEnd('\n', '\r'));
				}
				Plugin.errorStackTrace = stringBuilder.ToString();
			}
			UIFatalErrorTip.instance.ShowError(Plugin.errorString, Plugin.errorStackTrace);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)ex);
		}
	}

	[HarmonyPrefix]
	[HarmonyPatch("ShowError")]
	private static void ShowError_Prefix(UIFatalErrorTip __instance)
	{
		//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)
		if (string.IsNullOrEmpty(__instance.errorLogText.text) || waitingToRefresh)
		{
			astroId = TrackEntity_Patch.AstroId;
			entityId = TrackEntity_Patch.EntityId;
			localPos = TrackEntity_Patch.LocalPos;
		}
		if (waitingToRefresh)
		{
			waitingToRefresh = false;
			UIFatalErrorTip.ClearError();
			TryNavigate();
		}
	}

	[HarmonyPostfix]
	[HarmonyPriority(200)]
	[HarmonyPatch("_OnOpen")]
	private static void OnOpen_Postfix(UIFatalErrorTip __instance)
	{
		if (!((Object)(object)btnClose != (Object)null) && !((Object)(object)btnCopy != (Object)null) && !((Object)(object)btnInspect != (Object)null))
		{
			TryCreateButton(delegate
			{
				CreateCloseBtn(__instance);
			}, "Close Button");
			TryCreateButton(delegate
			{
				CreateCopyBtn(__instance);
			}, "Copy Button");
			TryCreateButton(delegate
			{
				CreateInspectBtn(__instance);
			}, "Inspect Button");
			((Component)((Component)__instance).transform.Find("tip-text-0")).GetComponent<Text>().text = GetShortTitle();
			((Component)((Component)__instance).transform.Find("tip-text-1")).GetComponent<Text>().text = GetShortTitle();
			Object.Destroy((Object)(object)((Component)((Component)__instance).transform.Find("tip-text-0")).GetComponent<Localizer>());
			Object.Destroy((Object)(object)((Component)((Component)__instance).transform.Find("tip-text-1")).GetComponent<Localizer>());
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch("_OnClose")]
	private static void OnClose_Postfix()
	{
		if ((Object)(object)btnClose != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)btnClose).gameObject);
			btnClose = null;
		}
		if ((Object)(object)btnCopy != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)btnCopy).gameObject);
			btnCopy = null;
		}
		if ((Object)(object)btnInspect != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)btnInspect).gameObject);
			btnInspect = null;
		}
		TrackEntity_Patch.ResetId();
	}

	private static void TryCreateButton(Action createAction, string buttonName)
	{
		try
		{
			createAction();
		}
		catch (Exception arg)
		{
			Plugin.Log.LogWarning((object)$"{buttonName} did not patch!\n{arg}");
		}
	}

	private static UIButton CreateButton(string path, Transform parent, Vector3 positionOffset, Action<int> onClickAction)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = GameObject.Find(path);
		if ((Object)(object)val == (Object)null)
		{
			Plugin.Log.LogWarning((object)("Can't find " + path));
			return null;
		}
		return CreateButton(val, parent, positionOffset, onClickAction);
	}

	private static UIButton CreateButton(GameObject originalGo, Transform parent, Vector3 positionOffset, Action<int> onClickAction)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: 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_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)originalGo != (Object)null)
		{
			GameObject obj = Object.Instantiate<GameObject>(originalGo, parent);
			RectTransform val = (RectTransform)obj.transform;
			val.anchorMin = Vector2.up;
			val.anchorMax = Vector2.up;
			val.pivot = Vector2.up;
			val.anchoredPosition = Vector2.op_Implicit(positionOffset);
			obj.SetActive(true);
			UIButton component = obj.GetComponent<UIButton>();
			component.onClick += onClickAction;
			component.tips.corner = 1;
			return component;
		}
		return null;
	}

	private static void CreateCloseBtn(UIFatalErrorTip __instance)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)btnClose != (Object)null))
		{
			btnClose = CreateButton("UI Root/Overlay Canvas/In Game/Common Tools/Color Palette Panel/panel-bg/btn-box/close-wnd-btn", ((Component)__instance).transform, new Vector3(-5f, 0f, 0f), OnCloseClick);
			if (!((Object)(object)btnClose != (Object)null))
			{
				btnClose = CreateButton("UI Root/Overlay Canvas/In Game/Windows/Window Template/panel-bg/btn-box/close-btn", ((Component)__instance).transform, new Vector3(-5f, 0f, 0f), OnCloseClick);
			}
		}
	}

	private static void CreateCopyBtn(UIFatalErrorTip __instance)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)btnCopy != (Object)null))
		{
			btnCopy = CreateButton("UI Root/Overlay Canvas/In Game/Windows/Dyson Sphere Editor/Dyson Editor Control Panel/hierarchy/layers/blueprint-group/blueprint-2/copy-button", ((Component)__instance).transform, new Vector3(5f, -55f, 0f), OnCopyClick);
			btnCopy.tips.tipTitle = "Copy Error Message";
			btnCopy.tips.tipText = "Copy the message to clipboard\nShift-click to copy the mod list too";
		}
	}

	private static void CreateInspectBtn(UIFatalErrorTip __instance)
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)btnInspect != (Object)null) && GameMain.mainPlayer != null)
		{
			btnInspect = CreateButton(((Component)UIRoot.instance.uiGame.researchQueue.pauseButton).gameObject, ((Component)__instance).transform, new Vector3(20f, -80f, 0f), OnInspectClick);
			((Component)((Component)btnInspect).transform.Find("icon")).GetComponent<Image>().sprite = ((Component)((Component)UIRoot.instance.uiGame.starmap.cursorFunctionButton2).transform.Find("icon")).GetComponent<Image>().sprite;
			((Component)btnInspect).transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
			btnInspect.onRightClick += ToggleTrackMode;
			btnInspect.tips.tipTitle = "Find The Error Entity";
			btnInspect.tips.tipText = "Left click to navigate\nRight click to toggle debug mode";
			if (astroId > 0 && astroId % 100 != 0)
			{
				string arg = GameMain.galaxy.PlanetById(astroId).displayName ?? "";
				btnInspect.tips.tipText += $"\nentity: {entityId} at [{astroId}] {arg}";
			}
			SetInsepctButton();
		}
	}

	private static string GetFullTitle()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append("Error report: Game version ");
		Version gameVersion = GameConfig.gameVersion;
		stringBuilder.Append(((object)(Version)(ref gameVersion)).ToString());
		stringBuilder.Append('.');
		stringBuilder.Append(GameConfig.gameVersion.Build);
		stringBuilder.Append(" with ");
		stringBuilder.Append(Chainloader.PluginInfos.Values.Count);
		stringBuilder.AppendLine(" mods used.");
		foreach (PluginInfo value in Chainloader.PluginInfos.Values)
		{
			stringBuilder.Append('[');
			stringBuilder.Append(value.Metadata.Name);
			stringBuilder.Append(value.Metadata.Version);
			stringBuilder.Append("] ");
		}
		return stringBuilder.ToString();
	}

	private static string GetShortTitle()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append("Error report: Game version ");
		Version gameVersion = GameConfig.gameVersion;
		stringBuilder.Append(((object)(Version)(ref gameVersion)).ToString());
		stringBuilder.Append('.');
		stringBuilder.Append(GameConfig.gameVersion.Build);
		stringBuilder.Append(" with ");
		stringBuilder.Append(Chainloader.PluginInfos.Values.Count);
		stringBuilder.Append(" mods used.");
		if (!string.IsNullOrWhiteSpace(ExtarTitleString))
		{
			stringBuilder.AppendLine();
			stringBuilder.Append(ExtarTitleString);
		}
		return stringBuilder.ToString();
	}

	private static void OnCopyClick(int id)
	{
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("```ini");
		if (VFInput.shift)
		{
			stringBuilder.AppendLine(GetFullTitle());
		}
		else
		{
			stringBuilder.AppendLine(GetShortTitle());
		}
		string[] array = UIFatalErrorTip.instance.errorLogText.text.Split('\n', '\r');
		foreach (string text in array)
		{
			if (!string.IsNullOrEmpty(text))
			{
				int num = text.LastIndexOf(" <", StringComparison.Ordinal);
				int num2 = text.LastIndexOf(">:", StringComparison.Ordinal);
				if (num != -1 && num2 > num)
				{
					stringBuilder.AppendLine(text.Remove(num, num2 - num + 2));
				}
				else
				{
					stringBuilder.AppendLine(text);
				}
			}
		}
		stringBuilder.Replace(" (at", "; (");
		stringBuilder.Replace(" inIL_", " ;IL_");
		stringBuilder.AppendLine("```");
		GUIUtility.systemCopyBuffer = stringBuilder.ToString();
		UIRealtimeTip.Popup("Error message copied!", false, 0);
	}

	public static void OnCloseClick(int _)
	{
		waitingToRefresh = false;
		UIFatalErrorTip.ClearError();
	}

	private static void OnInspectClick(int _)
	{
		if (astroId <= 0)
		{
			if (!TrackEntity_Patch.Active)
			{
				waitingToRefresh = true;
				ToggleTrackMode(0);
			}
		}
		else
		{
			TryNavigate();
		}
	}

	internal static void TryNavigate()
	{
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		if (astroId <= 0 || GameMain.mainPlayer == null)
		{
			return;
		}
		if (astroId % 100 != 0 && GameMain.data.localPlanet?.id == astroId)
		{
			PlanetFactory factory = GameMain.data.localPlanet.factory;
			if (entityId >= factory.entityPool.Length)
			{
				UIRealtimeTip.Popup($"EntityId {entityId} exceed Pool length {factory.entityPool.Length}!", true, 0);
				return;
			}
			localPos = ((entityId > 0) ? factory.entityPool[entityId].pos : localPos);
			UIRoot.instance.uiGame.globemap.MoveToViewTargetTwoStep(localPos, ((Vector3)(ref localPos)).magnitude - GameMain.data.localPlanet.realRadius);
			GameMain.data.mainPlayer.Order(OrderNode.MoveTo(localPos), false);
		}
		else
		{
			GameMain.mainPlayer.navigation.indicatorAstroId = astroId;
		}
	}

	private static void ToggleTrackMode(int _)
	{
		try
		{
			TrackEntity_Patch.Enable(!TrackEntity_Patch.Active);
			SetInsepctButton();
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Can't enable tracking!\n" + ex));
		}
	}

	private static void SetInsepctButton()
	{
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)btnInspect == (Object)null) && btnInspect.transitions.Length != 0)
		{
			btnInspect.CloseTip();
			if (TrackEntity_Patch.Active)
			{
				btnInspect.tips.tipTitle = "Find The Error Entity (ON)";
				btnInspect.transitions[0].normalColor = new Color(0.7f, 0.7f, 0.3f, 0.4f);
				btnInspect.transitions[0].mouseoverColor = new Color(0.7f, 0.7f, 0.3f, 0.5f);
			}
			else
			{
				btnInspect.tips.tipTitle = "Find The Error Entity (OFF)";
				btnInspect.transitions[0].normalColor = new Color(0.2392f, 0.6f, 0.9f, 0.078f);
				btnInspect.transitions[0].mouseoverColor = new Color(0.2392f, 0.6f, 0.9f, 0.178f);
			}
		}
	}
}