Decompiled source of Empress CompatibilityChecker v1.0.6

EmpressCompatChecker.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Omniscye")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c735220b7fa1eafbd68dd0be8091fcc579b25e55")]
[assembly: AssemblyProduct("EmpressCompatChecker")]
[assembly: AssemblyTitle("EmpressCompatChecker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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;
		}
	}
}
namespace EMpressCompatChecker
{
	internal static class HarmonyCompatUtil
	{
		internal class PatchRecord
		{
			public string Owner = string.Empty;

			public int Priority;

			public string[] Before = Array.Empty<string>();

			public string[] After = Array.Empty<string>();

			public MethodInfo? Method;
		}

		internal class PatchBundle
		{
			public List<PatchRecord> Prefixes = new List<PatchRecord>();

			public List<PatchRecord> Postfixes = new List<PatchRecord>();

			public List<PatchRecord> Transpilers = new List<PatchRecord>();

			public List<PatchRecord> Finalizers = new List<PatchRecord>();

			public HashSet<string> AllOwners
			{
				get
				{
					HashSet<string> hashSet = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
					foreach (PatchRecord prefix in Prefixes)
					{
						hashSet.Add(prefix.Owner);
					}
					foreach (PatchRecord postfix in Postfixes)
					{
						hashSet.Add(postfix.Owner);
					}
					foreach (PatchRecord transpiler in Transpilers)
					{
						hashSet.Add(transpiler.Owner);
					}
					foreach (PatchRecord finalizer in Finalizers)
					{
						hashSet.Add(finalizer.Owner);
					}
					return hashSet;
				}
			}
		}

		internal static PatchBundle GetPatches(MethodBase m)
		{
			PatchBundle patchBundle = new PatchBundle();
			Type type = Type.GetType("HarmonyLib.Harmony, HarmonyLib") ?? Type.GetType("HarmonyLib.Harmony, 0Harmony") ?? typeof(Harmony);
			MethodInfo method = type.GetMethod("GetPatchInfo", BindingFlags.Static | BindingFlags.Public);
			if (method == null)
			{
				return patchBundle;
			}
			object obj = method.Invoke(null, new object[1] { m });
			if (obj == null)
			{
				return patchBundle;
			}
			Fill(patchBundle.Prefixes, obj, "Prefixes");
			Fill(patchBundle.Postfixes, obj, "Postfixes");
			Fill(patchBundle.Transpilers, obj, "Transpilers");
			Fill(patchBundle.Finalizers, obj, "Finalizers");
			return patchBundle;
		}

		private static void Fill(List<PatchRecord> dst, object info, string propName)
		{
			Type type = info.GetType();
			MemberInfo memberInfo = (MemberInfo)(type.GetProperty(propName) ?? ((object)type.GetProperty(propName.ToLowerInvariant())) ?? ((object)(type.GetField(propName) ?? type.GetField(propName.ToLowerInvariant()))));
			if (memberInfo == null)
			{
				return;
			}
			object obj = ((memberInfo is PropertyInfo propertyInfo) ? propertyInfo.GetValue(info) : ((memberInfo is FieldInfo fieldInfo) ? fieldInfo.GetValue(info) : null));
			if (obj == null || !(obj is IEnumerable enumerable))
			{
				return;
			}
			foreach (object item in enumerable)
			{
				if (item != null)
				{
					PatchRecord patchRecord = new PatchRecord();
					object obj2 = GetString(item, "owner") ?? GetString(item, "Owner");
					if (obj2 == null)
					{
						obj2 = "";
					}
					patchRecord.Owner = (string)obj2;
					patchRecord.Priority = GetInt(item, "priority") ?? GetInt(item, "Priority").GetValueOrDefault();
					patchRecord.Before = GetStringArray(item, "before") ?? GetStringArray(item, "Before") ?? Array.Empty<string>();
					patchRecord.After = GetStringArray(item, "after") ?? GetStringArray(item, "After") ?? Array.Empty<string>();
					patchRecord.Method = (GetObj(item, "patchMethod") as MethodInfo) ?? (GetObj(item, "PatchMethod") as MethodInfo);
					dst.Add(patchRecord);
				}
			}
		}

		private static object? GetObj(object target, string name)
		{
			Type type = target.GetType();
			PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				return property.GetValue(target);
			}
			FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return field.GetValue(target);
			}
			return null;
		}

		private static string? GetString(object target, string name)
		{
			return GetObj(target, name) as string;
		}

		private static int? GetInt(object target, string name)
		{
			object obj = GetObj(target, name);
			if (obj == null)
			{
				return null;
			}
			if (obj is int value)
			{
				return value;
			}
			try
			{
				return Convert.ToInt32(obj);
			}
			catch
			{
				return null;
			}
		}

		private static string[]? GetStringArray(object target, string name)
		{
			object obj = GetObj(target, name);
			if (obj == null)
			{
				return null;
			}
			if (obj is string[] result)
			{
				return result;
			}
			if (obj is IEnumerable enumerable)
			{
				List<string> list = new List<string>();
				foreach (object item in enumerable)
				{
					if (item != null)
					{
						list.Add(item.ToString() ?? "");
					}
				}
				return list.ToArray();
			}
			return null;
		}
	}
	internal class ILSig
	{
		public HashSet<string> Tokens = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
	}
	internal static class ILDiffUtil
	{
		private static readonly Dictionary<short, OpCode> _opCodes = BuildOpMap();

		private static Dictionary<short, OpCode> BuildOpMap()
		{
			Dictionary<short, OpCode> dictionary = new Dictionary<short, OpCode>();
			FieldInfo[] fields = typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public);
			FieldInfo[] array = fields;
			foreach (FieldInfo fieldInfo in array)
			{
				if (fieldInfo.GetValue(null) is OpCode value)
				{
					dictionary[value.Value] = value;
				}
			}
			return dictionary;
		}

		internal static ILSig BuildSig(MethodInfo mi)
		{
			ILSig iLSig = new ILSig();
			try
			{
				MethodBody methodBody = mi.GetMethodBody();
				if (methodBody == null)
				{
					return iLSig;
				}
				byte[] iLAsByteArray = methodBody.GetILAsByteArray();
				if (iLAsByteArray == null)
				{
					return iLSig;
				}
				int num = 0;
				while (num < iLAsByteArray.Length)
				{
					byte b = iLAsByteArray[num++];
					OpCode value;
					if (b == 254)
					{
						byte b2 = iLAsByteArray[num++];
						short key = (short)(0xFE00 | b2);
						if (!_opCodes.TryGetValue(key, out value))
						{
							continue;
						}
					}
					else if (!_opCodes.TryGetValue(b, out value))
					{
						continue;
					}
					switch (value.OperandType)
					{
					case OperandType.InlineBrTarget:
					case OperandType.InlineField:
					case OperandType.InlineI:
					case OperandType.InlineI8:
					case OperandType.InlineMethod:
					case OperandType.InlineR:
					case OperandType.InlineSig:
					case OperandType.InlineString:
					case OperandType.InlineTok:
					case OperandType.InlineType:
					case OperandType.ShortInlineR:
						num += OperandSize(value.OperandType);
						break;
					case OperandType.ShortInlineBrTarget:
					case OperandType.ShortInlineI:
					case OperandType.ShortInlineVar:
						num++;
						break;
					case OperandType.InlineVar:
						num += 2;
						break;
					case OperandType.InlineSwitch:
					{
						int num2 = BitConverter.ToInt32(iLAsByteArray, num);
						num += 4 + num2 * 4;
						break;
					}
					}
					iLSig.Tokens.Add(value.Name);
				}
			}
			catch
			{
			}
			return iLSig;
		}

		private static int OperandSize(OperandType t)
		{
			return t switch
			{
				OperandType.InlineBrTarget => 4, 
				OperandType.InlineField => 4, 
				OperandType.InlineMethod => 4, 
				OperandType.InlineSig => 4, 
				OperandType.InlineString => 4, 
				OperandType.InlineTok => 4, 
				OperandType.InlineType => 4, 
				OperandType.ShortInlineR => 4, 
				OperandType.InlineI => 4, 
				OperandType.InlineR => 8, 
				OperandType.InlineI8 => 8, 
				_ => 0, 
			};
		}

		internal static int Similarity(ILSig a, ILSig b)
		{
			if (a == null || b == null)
			{
				return 0;
			}
			int num = 0;
			foreach (string token in a.Tokens)
			{
				if (b.Tokens.Contains(token))
				{
					num++;
				}
			}
			int num2 = a.Tokens.Count + b.Tokens.Count - num;
			if (num2 <= 0)
			{
				return 0;
			}
			return (int)Math.Round(100.0 * (double)num / (double)num2);
		}
	}
	internal static class TraceRuntime
	{
		internal struct TraceLine
		{
			public string T;

			public string Kind;

			public string Target;

			public int Thread;

			public double DurMs;

			public string Error;
		}

		private static string _id = "Empress.Trace";

		private static Harmony _h = null;

		private static HashSet<MethodBase> _patched = new HashSet<MethodBase>();

		private static int _cap = 2000;

		private static readonly object _lock = new object();

		private static readonly List<TraceLine> _lines = new List<TraceLine>(_cap);

		[ThreadStatic]
		private static bool _inTrace;

		internal static void Init(string id)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			_id = id;
			_h = new Harmony(_id);
		}

		internal static void PatchAll(IEnumerable<MethodBase> methods)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			foreach (MethodBase method in methods)
			{
				if (!(method == null) && !_patched.Contains(method))
				{
					try
					{
						HarmonyMethod val = new HarmonyMethod(typeof(TraceRuntime).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic));
						val.priority = int.MaxValue;
						HarmonyMethod val2 = new HarmonyMethod(typeof(TraceRuntime).GetMethod("Postfix", BindingFlags.Static | BindingFlags.NonPublic));
						val2.priority = int.MinValue;
						HarmonyMethod val3 = new HarmonyMethod(typeof(TraceRuntime).GetMethod("Finalizer", BindingFlags.Static | BindingFlags.NonPublic));
						val3.priority = int.MinValue;
						_h.Patch(method, val, val2, (HarmonyMethod)null, val3, (HarmonyMethod)null);
						_patched.Add(method);
					}
					catch
					{
					}
				}
			}
		}

		internal static void UnpatchAll()
		{
			try
			{
				_h.UnpatchSelf();
			}
			catch
			{
			}
			_patched.Clear();
		}

		private static void Add(string kind, string target, double durMs, string err)
		{
			TraceLine traceLine = default(TraceLine);
			traceLine.T = DateTime.Now.ToString("HH:mm:ss.fff");
			traceLine.Kind = kind;
			traceLine.Target = target;
			traceLine.Thread = Thread.CurrentThread.ManagedThreadId;
			traceLine.DurMs = durMs;
			traceLine.Error = err;
			TraceLine item = traceLine;
			lock (_lock)
			{
				if (_lines.Count >= _cap)
				{
					_lines.RemoveAt(0);
				}
				_lines.Add(item);
			}
		}

		private static string Name(MethodBase m)
		{
			string text = ((m.DeclaringType != null) ? m.DeclaringType.FullName : "?");
			return text + "::" + m.Name;
		}

		private static void Prefix(MethodBase __originalMethod, ref long __state)
		{
			if (!_inTrace)
			{
				_inTrace = true;
				__state = Stopwatch.GetTimestamp();
				Add("enter", Name(__originalMethod), 0.0, "");
				_inTrace = false;
			}
		}

		private static void Postfix(MethodBase __originalMethod, long __state)
		{
			if (!_inTrace)
			{
				_inTrace = true;
				double durMs = (double)(Stopwatch.GetTimestamp() - __state) * 1000.0 / (double)Stopwatch.Frequency;
				Add("exit", Name(__originalMethod), durMs, "");
				_inTrace = false;
			}
		}

		private static Exception Finalizer(MethodBase __originalMethod, Exception __exception, long __state)
		{
			if (_inTrace)
			{
				return __exception;
			}
			_inTrace = true;
			double durMs = (double)(Stopwatch.GetTimestamp() - __state) * 1000.0 / (double)Stopwatch.Frequency;
			string err = ((__exception != null) ? __exception.GetType().Name : "");
			if (__exception != null)
			{
				Add("error", Name(__originalMethod), durMs, err);
			}
			_inTrace = false;
			return __exception;
		}

		internal static void Clear()
		{
			lock (_lock)
			{
				_lines.Clear();
			}
		}

		internal static List<TraceLine> Snapshot()
		{
			lock (_lock)
			{
				return _lines.ToList();
			}
		}
	}
	[BepInPlugin("Empress.EmpressCompatChecker", "EmpressCompatChecker", "1.2.0")]
	public class EMpressCompatChecker : BaseUnityPlugin
	{
		[HarmonyPatch]
		private static class Patch_CameraAim_Update
		{
			private static MethodBase TargetMethod()
			{
				return FindTypeBySimpleName("CameraAim")?.GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? null;
			}

			private static bool Prefix()
			{
				return !UIActive;
			}
		}

		private class PluginRow
		{
			public string GUID = string.Empty;

			public string Name = string.Empty;

			public string Version = string.Empty;

			public string Location = string.Empty;

			public string FileName = string.Empty;

			public bool Active;

			public bool DisableNextBoot;

			public string HarmonyIdCandidate = string.Empty;

			public PluginInfo? Info;

			public HashSet<string> Deps = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
		}

		private class ConflictRow
		{
			public string KeyFile = string.Empty;

			public List<string> Paths = new List<string>();

			public HashSet<string> FileNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
		}

		private class MethodOverlap
		{
			public string Target = string.Empty;

			public List<OwnerCount> Owners = new List<OwnerCount>();

			public HashSet<string> OwnerIds = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);

			public HashSet<string> GroupKeys = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);

			public int GroupCount => GroupKeys.Count;
		}

		private struct PatchCounts
		{
			public int Pre;

			public int Post;

			public int Trans;

			public int Final;
		}

		private class OwnerCount
		{
			public string MatchKey = string.Empty;

			public string Display = string.Empty;

			public PatchCounts Counts;
		}

		private class AnalyzerRow
		{
			public string Target = string.Empty;

			public List<AnalyzerPatch> Patches = new List<AnalyzerPatch>();

			public string Risk = string.Empty;

			public string Reason = string.Empty;

			public List<string> Notes = new List<string>();
		}

		private class AnalyzerPatch
		{
			public string Owner = string.Empty;

			public string Display = string.Empty;

			public string Kind = string.Empty;

			public int Priority;

			public string[] Before = Array.Empty<string>();

			public string[] After = Array.Empty<string>();

			public bool ReturnsBool;

			public bool HasRunOriginalParam;

			public bool ModifiesResult;
		}

		private bool showWindow;

		private Rect windowRect = new Rect(80f, 80f, 1200f, 800f);

		private Vector2 scrollLeft;

		private Vector2 scrollRight;

		private Vector2 scrollAnalyzer;

		private Vector2 scrollTrace;

		private string search = string.Empty;

		private List<PluginRow> plugins = new List<PluginRow>();

		private List<ConflictRow> duplicateDlls = new List<ConflictRow>();

		private List<MethodOverlap> overlaps = new List<MethodOverlap>();

		private List<AnalyzerRow> analysis = new List<AnalyzerRow>();

		private GUIStyle windowStyle;

		private GUIStyle headerStyle;

		private GUIStyle titleStyle;

		private GUIStyle labelStyle;

		private GUIStyle labelWhiteStyle;

		private GUIStyle labelSkyStyle;

		private GUIStyle buttonStyle;

		private GUIStyle toggleStyle;

		private GUIStyle textFieldStyle;

		private GUIStyle boxStyle;

		private GUIStyle scrollStyle;

		private GUIStyle terminalStyle;

		private GUIStyle terminalBoxStyle;

		private Texture2D bgTex;

		private Texture2D dotRed;

		private Texture2D dotYellow;

		private Texture2D evilPink;

		private string disabledFolder = string.Empty;

		private float openTimer;

		private CursorLockMode _prevLock;

		private bool _prevVisible;

		private bool _cursorTaken;

		private bool _rebuildRequested;

		private int activeTab;

		private ConfigEntry<bool> cfgDeep;

		private ConfigEntry<bool> cfgExt;

		private ConfigEntry<bool> cfgTrace;

		private ConfigEntry<bool> cfgIL;

		internal static EMpressCompatChecker Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		internal static bool UIActive => (Object)(object)Instance != (Object)null && Instance.showWindow;

		private void Awake()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_004d: Expected O, but got Unknown
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
			cfgDeep = ((BaseUnityPlugin)this).Config.Bind<bool>("Analyzer", "EnableDeepAnalyzer", false, "");
			cfgExt = ((BaseUnityPlugin)this).Config.Bind<bool>("Analyzer", "EnableExtendedHeuristics", false, "");
			cfgTrace = ((BaseUnityPlugin)this).Config.Bind<bool>("Analyzer", "EnableRuntimeTrace", false, "");
			cfgIL = ((BaseUnityPlugin)this).Config.Bind<bool>("Analyzer", "EnableILSignatures", false, "");
			disabledFolder = Path.GetFullPath(Path.Combine(Paths.PluginPath, "..", "disabled"));
			BuildPlugins();
			BuildDuplicates();
			BuildPatchGraph();
			if (cfgDeep.Value)
			{
				BuildAnalysis();
			}
			if (cfgTrace.Value)
			{
				ApplyTracePatches();
			}
			showWindow = false;
			openTimer = 5f;
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} ready");
		}

		private void Update()
		{
			if (openTimer > 0f)
			{
				openTimer -= Time.unscaledDeltaTime;
				if (openTimer <= 0f)
				{
					BuildPlugins();
					BuildDuplicates();
					BuildPatchGraph();
					if (cfgDeep.Value)
					{
						BuildAnalysis();
					}
					if (cfgTrace.Value)
					{
						ApplyTracePatches();
					}
					showWindow = true;
					TakeCursor();
				}
			}
			if (Input.GetKey((KeyCode)306) && Input.GetKeyDown((KeyCode)291))
			{
				showWindow = !showWindow;
				if (showWindow)
				{
					TakeCursor();
				}
				else
				{
					RestoreCursor();
				}
			}
			if (showWindow)
			{
				KeepCursorFree();
			}
			if (_rebuildRequested)
			{
				_rebuildRequested = false;
				BuildPlugins();
				BuildDuplicates();
				BuildPatchGraph();
				if (cfgDeep.Value)
				{
					BuildAnalysis();
				}
				if (cfgTrace.Value)
				{
					ApplyTracePatches();
				}
			}
		}

		private void LateUpdate()
		{
			if (showWindow)
			{
				KeepCursorFree();
			}
		}

		private void OnGUI()
		{
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Expected O, but got Unknown
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			if (windowStyle == null)
			{
				InitStyles();
			}
			if (showWindow)
			{
				float num = Mathf.Min((float)Screen.width - 40f, 1600f);
				float num2 = Mathf.Min((float)Screen.height - 40f, 1000f);
				if (Mathf.Abs(((Rect)(ref windowRect)).width - num) > 1f || Mathf.Abs(((Rect)(ref windowRect)).height - num2) > 1f)
				{
					((Rect)(ref windowRect)).width = num;
					((Rect)(ref windowRect)).height = num2;
				}
				((Rect)(ref windowRect)).x = Mathf.Clamp(((Rect)(ref windowRect)).x, 10f, Mathf.Max(10f, (float)Screen.width - ((Rect)(ref windowRect)).width - 10f));
				((Rect)(ref windowRect)).y = Mathf.Clamp(((Rect)(ref windowRect)).y, 10f, Mathf.Max(10f, (float)Screen.height - ((Rect)(ref windowRect)).height - 10f));
				GUI.color = Color.white;
				GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)bgTex);
				windowRect = GUILayout.Window(8842201, windowRect, new WindowFunction(DrawWindow), string.Empty, windowStyle, Array.Empty<GUILayoutOption>());
			}
		}

		private void InitStyles()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Expected O, but got Unknown
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Expected O, but got Unknown
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Expected O, but got Unknown
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Expected O, but got Unknown
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Expected O, but got Unknown
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Expected O, but got Unknown
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Expected O, but got Unknown
			//IL_02fd: Expected O, but got Unknown
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Expected O, but got Unknown
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0427: Unknown result type (might be due to invalid IL or missing references)
			//IL_0444: Unknown result type (might be due to invalid IL or missing references)
			//IL_0454: Unknown result type (might be due to invalid IL or missing references)
			//IL_045a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_048e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0494: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d1: Expected O, but got Unknown
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_050e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0513: Unknown result type (might be due to invalid IL or missing references)
			//IL_051d: Expected O, but got Unknown
			//IL_0523: Expected O, but got Unknown
			//IL_052e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0533: Unknown result type (might be due to invalid IL or missing references)
			//IL_0550: Unknown result type (might be due to invalid IL or missing references)
			//IL_0565: Expected O, but got Unknown
			//IL_0570: Unknown result type (might be due to invalid IL or missing references)
			//IL_0575: Unknown result type (might be due to invalid IL or missing references)
			//IL_057e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0593: Unknown result type (might be due to invalid IL or missing references)
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b3: Expected O, but got Unknown
			//IL_05be: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ff: Expected O, but got Unknown
			//IL_0600: Unknown result type (might be due to invalid IL or missing references)
			//IL_0605: Unknown result type (might be due to invalid IL or missing references)
			//IL_060f: Expected O, but got Unknown
			//IL_0615: Expected O, but got Unknown
			evilPink = MakeTex(2, 2, new Color(1f, 0.1f, 0.6f));
			bgTex = MakeTex(2, 2, new Color(0f, 0f, 0f, 1f));
			dotRed = MakeTex(1, 1, new Color(1f, 0.2f, 0.4f));
			dotYellow = MakeTex(1, 1, new Color(1f, 0.9f, 0.3f));
			windowStyle = new GUIStyle(GUI.skin.window);
			windowStyle.normal.background = bgTex;
			windowStyle.hover.background = bgTex;
			windowStyle.active.background = bgTex;
			windowStyle.focused.background = bgTex;
			windowStyle.onNormal.background = bgTex;
			windowStyle.onHover.background = bgTex;
			windowStyle.onActive.background = bgTex;
			windowStyle.onFocused.background = bgTex;
			windowStyle.border = new RectOffset(20, 20, 40, 20);
			windowStyle.overflow = new RectOffset(10, 10, 10, 10);
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 28,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			val.normal.textColor = new Color(1f, 0.3f, 0.8f);
			titleStyle = val;
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 20,
				fontStyle = (FontStyle)1
			};
			val2.normal.textColor = new Color(1f, 0.4f, 0.9f);
			headerStyle = val2;
			Color textColor = default(Color);
			((Color)(ref textColor))..ctor(1f, 0.41f, 0.71f);
			GUIStyle val3 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 13
			};
			val3.normal.textColor = textColor;
			labelStyle = val3;
			labelWhiteStyle = new GUIStyle(labelStyle);
			labelWhiteStyle.normal.textColor = Color.white;
			labelSkyStyle = new GUIStyle(labelStyle);
			labelSkyStyle.normal.textColor = new Color(0.4f, 0.8f, 1f);
			buttonStyle = new GUIStyle(GUI.skin.button)
			{
				fontSize = 14,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4,
				padding = new RectOffset(8, 8, 6, 6)
			};
			buttonStyle.normal.background = MakeTex(2, 2, new Color(0.9f, 0.1f, 0.5f));
			buttonStyle.hover.background = MakeTex(2, 2, new Color(1f, 0.3f, 0.7f));
			buttonStyle.active.background = MakeTex(2, 2, new Color(0.7f, 0f, 0.4f));
			buttonStyle.normal.textColor = Color.white;
			buttonStyle.hover.textColor = Color.white;
			buttonStyle.active.textColor = Color.white;
			GUIStyle val4 = new GUIStyle(GUI.skin.toggle)
			{
				fontSize = 13,
				fontStyle = (FontStyle)1
			};
			val4.normal.textColor = Color.magenta;
			val4.onNormal.textColor = Color.cyan;
			toggleStyle = val4;
			GUIStyle val5 = new GUIStyle(GUI.skin.textField)
			{
				fontSize = 14
			};
			val5.normal.background = MakeTex(2, 2, new Color(0f, 0f, 0f, 1f));
			val5.normal.textColor = textColor;
			val5.focused.background = MakeTex(2, 2, new Color(0.08f, 0.08f, 0.08f, 1f));
			val5.focused.textColor = Color.white;
			val5.hover.background = MakeTex(2, 2, new Color(0.05f, 0.05f, 0.05f, 1f));
			textFieldStyle = val5;
			GUIStyle val6 = new GUIStyle(GUI.skin.box);
			val6.normal.background = MakeTex(2, 2, new Color(0f, 0f, 0f, 1f));
			val6.border = new RectOffset(4, 4, 4, 4);
			boxStyle = val6;
			GUIStyle val7 = new GUIStyle(GUI.skin.scrollView);
			val7.normal.background = MakeTex(2, 2, new Color(0f, 0f, 0f, 0f));
			scrollStyle = val7;
			GUIStyle val8 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 13
			};
			val8.normal.textColor = new Color(0.6f, 1f, 0.7f);
			val8.wordWrap = false;
			val8.alignment = (TextAnchor)0;
			terminalStyle = val8;
			GUIStyle val9 = new GUIStyle(GUI.skin.box);
			val9.normal.background = MakeTex(2, 2, new Color(0f, 0.05f, 0f, 1f));
			val9.border = new RectOffset(4, 4, 4, 4);
			val9.padding = new RectOffset(8, 8, 6, 6);
			terminalBoxStyle = val9;
		}

		private Texture2D MakeTex(int width, int height, Color col)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_002c: Expected O, but got Unknown
			Color[] array = (Color[])(object)new Color[width * height];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = col;
			}
			Texture2D val = new Texture2D(width, height);
			val.SetPixels(array);
			val.Apply();
			return val;
		}

		private void DrawWindow(int id)
		{
			//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.Label("EMPRESS COMPATIBILITY DOMINATRIX", titleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			GUILayout.Label($"Plugins: {plugins.Count} • Duplicates: {duplicateDlls.Count} • Conflicts: {overlaps.Count((MethodOverlap o) => o.GroupCount > 1)}", headerStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(15f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("SEARCH:", labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
			search = GUILayout.TextField(search, textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(300f) });
			if (GUILayout.Button("REBUILD", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }))
			{
				_rebuildRequested = true;
			}
			if (GUILayout.Button("CLOSE", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
			{
				showWindow = false;
				RestoreCursor();
			}
			GUILayout.FlexibleSpace();
			bool flag = GUILayout.Toggle(cfgDeep.Value, "DEEP", toggleStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			if (flag != cfgDeep.Value)
			{
				cfgDeep.Value = flag;
				if (cfgDeep.Value)
				{
					BuildAnalysis();
					activeTab = 1;
				}
				else
				{
					activeTab = 0;
				}
			}
			bool flag2 = GUILayout.Toggle(cfgExt.Value, "EXT", toggleStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
			if (flag2 != cfgExt.Value)
			{
				cfgExt.Value = flag2;
				if (cfgDeep.Value)
				{
					BuildAnalysis();
				}
			}
			bool flag3 = GUILayout.Toggle(cfgTrace.Value, "TRACE", toggleStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			if (flag3 != cfgTrace.Value)
			{
				cfgTrace.Value = flag3;
				if (cfgTrace.Value)
				{
					ApplyTracePatches();
					activeTab = 2;
				}
				else
				{
					TraceRuntime.UnpatchAll();
				}
			}
			bool flag4 = GUILayout.Toggle(cfgIL.Value, "IL", toggleStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			if (flag4 != cfgIL.Value)
			{
				cfgIL.Value = flag4;
				if (cfgDeep.Value)
				{
					BuildAnalysis();
				}
			}
			GUILayout.Space(12f);
			if (cfgDeep.Value)
			{
				if (GUILayout.Toggle(activeTab == 0, "OVERVIEW", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }))
				{
					activeTab = 0;
				}
				if (GUILayout.Toggle(activeTab == 1, "ANALYZER", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }))
				{
					activeTab = 1;
				}
			}
			if (cfgTrace.Value && GUILayout.Toggle(activeTab == 2, "TRACE", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }))
			{
				activeTab = 2;
			}
			GUILayout.Space(12f);
			GUILayout.Label("CTRL+F10", labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			GUILayout.Space(10f);
			if (activeTab == 2 && cfgTrace.Value)
			{
				DrawTraceTab();
			}
			else if (activeTab == 1 && cfgDeep.Value)
			{
				DrawAnalyzerTab();
			}
			else
			{
				DrawOverviewTab();
			}
			GUILayout.EndVertical();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 40f));
		}

		private void DrawOverviewTab()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			float num = ((Rect)(ref windowRect)).width - 40f;
			float num2 = 30f;
			float num3 = Mathf.Clamp(num * 0.65f, 680f, num - 420f - num2);
			float num4 = Mathf.Clamp(num - num3 - num2, 420f, num - num3 - num2);
			float num5 = 18f;
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num3) });
			GUILayout.Label("LOADED PLUGINS", headerStyle, Array.Empty<GUILayoutOption>());
			scrollLeft = GUILayout.BeginScrollView(scrollLeft, false, true, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num3) });
			float num6 = 20f;
			float num7 = 16f;
			float num8 = 90f;
			float num9 = 100f;
			float num10 = 100f;
			float num11 = num7 + num8 + num9 + num10 + 40f;
			float num12 = Mathf.Max(320f, num3 - num11 - num6);
			float num13 = 60f;
			float num14 = Mathf.Floor(num12 * 0.34f);
			float num15 = Mathf.Floor(num12 * 0.33f);
			float num16 = Mathf.Max(80f, num12 - num14 - num15 - num13);
			foreach (PluginRow item2 in FilteredPlugins().ToList())
			{
				GUILayout.BeginHorizontal(boxStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num3 - 8f) });
				if (HasOverlapFor(item2))
				{
					GUILayout.Label((Texture)(object)dotRed, (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(num7),
						GUILayout.Height(16f)
					});
				}
				else
				{
					GUILayout.Space(num7 + 2f);
				}
				GUILayout.Label(item2.Name, labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num14) });
				GUILayout.Label(item2.GUID, labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num15) });
				GUILayout.Label(item2.Version, labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num13) });
				GUILayout.Label(item2.FileName, labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num16) });
				GUILayout.FlexibleSpace();
				bool flag = GUILayout.Toggle(item2.Active, "ACTIVE", toggleStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num8) });
				if (flag != item2.Active)
				{
					item2.Active = flag;
					ToggleActive(item2);
				}
				bool flag2 = GUILayout.Toggle(item2.DisableNextBoot, "BANISH", toggleStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num9) });
				if (flag2 != item2.DisableNextBoot)
				{
					item2.DisableNextBoot = flag2;
					if (flag2)
					{
						DisableNowOrQueue(item2);
						_rebuildRequested = true;
					}
					else
					{
						TryRestore(item2);
						_rebuildRequested = true;
					}
				}
				if (!item2.Active && item2.DisableNextBoot && item2.Location.EndsWith(".dll.old", StringComparison.InvariantCultureIgnoreCase) && GUILayout.Button("ENABLE", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num10) }))
				{
					TryRestore(item2);
					_rebuildRequested = true;
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.EndScrollView();
			GUILayout.EndVertical();
			GUILayout.Space(num2);
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num4) });
			GUILayout.Label("PATCH OVERLAPS (EVIL)", headerStyle, Array.Empty<GUILayoutOption>());
			scrollRight = GUILayout.BeginScrollView(scrollRight, false, true, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num4) });
			List<MethodOverlap> list = overlaps.Where((MethodOverlap o) => o.GroupCount > 1).ToList();
			foreach (MethodOverlap item3 in list)
			{
				GUILayout.BeginVertical(boxStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num4 - num5 - 8f) });
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label((Texture)(object)dotYellow, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(16f),
					GUILayout.Height(16f)
				});
				float num17 = Mathf.Max(120f, num4 - num5 - 70f - 40f);
				GUILayout.Label(item3.Target, labelSkyStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num17) });
				GUILayout.FlexibleSpace();
				if (GUILayout.Button("COPY", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
				{
					GUIUtility.systemCopyBuffer = item3.Target;
				}
				GUILayout.EndHorizontal();
				foreach (OwnerCount item4 in item3.Owners.ToList())
				{
					PluginRow pluginRow = FindPluginByOwnerKeyOrAlias(item4.MatchKey);
					string item = ((pluginRow != null) ? pluginRow.Location : ("owner:" + item4.MatchKey));
					if (item3.GroupKeys.Contains(item))
					{
						GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
						float num18 = 200f;
						float num19 = Mathf.Max(140f, num4 - num5 - num18 - 120f - 40f);
						GUILayout.Label(item4.Display, labelWhiteStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num19) });
						GUILayout.Label($"pre:{item4.Counts.Pre} post:{item4.Counts.Post} trans:{item4.Counts.Trans} final:{item4.Counts.Final}", labelSkyStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num18) });
						GUILayout.FlexibleSpace();
						GUI.enabled = pluginRow != null && pluginRow.GUID != ((BaseUnityPlugin)this).Info.Metadata.GUID;
						if (GUILayout.Button("BANISH", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }) && pluginRow != null)
						{
							pluginRow.DisableNextBoot = true;
							DisableNowOrQueue(pluginRow);
							_rebuildRequested = true;
						}
						GUI.enabled = true;
						GUILayout.EndHorizontal();
					}
				}
				GUILayout.EndVertical();
				GUILayout.Space(4f);
			}
			GUILayout.EndScrollView();
			GUILayout.EndVertical();
			GUILayout.EndHorizontal();
		}

		private void DrawAnalyzerTab()
		{
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(((Rect)(ref windowRect)).width - 40f) });
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("DEEP ANALYZER", headerStyle, Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (!cfgIL.Value)
			{
				GUILayout.Label("Limits: no IL diffing", labelStyle, Array.Empty<GUILayoutOption>());
			}
			if (cfgIL.Value && !cfgExt.Value)
			{
				GUILayout.Label("IL sigs on - heuristics off", labelStyle, Array.Empty<GUILayoutOption>());
			}
			if (!cfgTrace.Value)
			{
				GUILayout.Label("Trace off", labelStyle, Array.Empty<GUILayoutOption>());
			}
			GUILayout.Space(10f);
			if (GUILayout.Button("SCAN", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
			{
				BuildAnalysis();
			}
			GUILayout.EndHorizontal();
			scrollAnalyzer = GUILayout.BeginScrollView(scrollAnalyzer, false, true, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(((Rect)(ref windowRect)).width - 40f) });
			foreach (AnalyzerRow item in analysis)
			{
				GUILayout.BeginVertical(terminalBoxStyle, Array.Empty<GUILayoutOption>());
				GUILayout.Label("[" + item.Risk + "] " + item.Target + " - " + item.Reason, terminalStyle, Array.Empty<GUILayoutOption>());
				foreach (AnalyzerPatch patch in item.Patches)
				{
					string text = "";
					if (patch.Kind == "Prefix" && patch.ReturnsBool)
					{
						text += " retBool";
					}
					if (patch.Kind == "Prefix" && patch.HasRunOriginalParam)
					{
						text += " runOriginal";
					}
					if (patch.Kind == "Postfix" && patch.ModifiesResult)
					{
						text += " modResult";
					}
					string text2 = "";
					if (patch.Before != null && patch.Before.Length != 0)
					{
						text2 = text2 + " before:" + string.Join(",", patch.Before);
					}
					if (patch.After != null && patch.After.Length != 0)
					{
						text2 = text2 + " after:" + string.Join(",", patch.After);
					}
					GUILayout.Label($"  {patch.Display} :: {patch.Kind} pri:{patch.Priority}{text} {text2}", terminalStyle, Array.Empty<GUILayoutOption>());
				}
				if (item.Notes != null && item.Notes.Count > 0)
				{
					foreach (string note in item.Notes)
					{
						GUILayout.Label("  - " + note, terminalStyle, Array.Empty<GUILayoutOption>());
					}
				}
				GUILayout.EndVertical();
				GUILayout.Space(6f);
			}
			GUILayout.EndScrollView();
			GUILayout.EndVertical();
			GUILayout.EndHorizontal();
		}

		private void DrawTraceTab()
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(((Rect)(ref windowRect)).width - 40f) });
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("RUNTIME TRACE", headerStyle, Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("CLEAR", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
			{
				TraceRuntime.Clear();
			}
			GUILayout.EndHorizontal();
			scrollTrace = GUILayout.BeginScrollView(scrollTrace, false, true, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(((Rect)(ref windowRect)).width - 40f) });
			List<TraceRuntime.TraceLine> list = TraceRuntime.Snapshot();
			foreach (TraceRuntime.TraceLine item in list)
			{
				GUILayout.BeginVertical(terminalBoxStyle, Array.Empty<GUILayoutOption>());
				GUILayout.Label($"{item.T} {item.Kind} {item.Target} dur:{item.DurMs}ms thr:{item.Thread} err:{item.Error}", terminalStyle, Array.Empty<GUILayoutOption>());
				GUILayout.EndVertical();
				GUILayout.Space(4f);
			}
			GUILayout.EndScrollView();
			GUILayout.EndVertical();
			GUILayout.EndHorizontal();
		}

		private IEnumerable<PluginRow> FilteredPlugins()
		{
			if (string.IsNullOrWhiteSpace(search))
			{
				return plugins;
			}
			string s = search.Trim().ToLowerInvariant();
			return plugins.Where((PluginRow p) => p.Name.ToLowerInvariant().Contains(s) || p.GUID.ToLowerInvariant().Contains(s) || p.FileName.ToLowerInvariant().Contains(s));
		}

		private void BuildPlugins()
		{
			List<PluginRow> list = new List<PluginRow>();
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				PluginInfo value = pluginInfo.Value;
				string location = value.Location;
				if (File.Exists(location) && !location.EndsWith(".dll.old", StringComparison.InvariantCultureIgnoreCase))
				{
					PluginRow item = new PluginRow
					{
						GUID = value.Metadata.GUID,
						Name = value.Metadata.Name,
						Version = value.Metadata.Version.ToString(),
						Location = location,
						FileName = Path.GetFileName(location),
						Active = ((Object)(object)value.Instance != (Object)null && ((Behaviour)value.Instance).isActiveAndEnabled),
						Info = value,
						HarmonyIdCandidate = value.Metadata.GUID,
						Deps = ReadDeps(value)
					};
					list.Add(item);
				}
			}
			try
			{
				string[] array = (Directory.Exists(Paths.PluginPath) ? Directory.GetFiles(Paths.PluginPath, "*.dll.old", SearchOption.AllDirectories) : Array.Empty<string>());
				string[] array2 = array;
				foreach (string text in array2)
				{
					string text2 = Path.GetFileName(text);
					if (text2.EndsWith(".dll.old", StringComparison.InvariantCultureIgnoreCase))
					{
						text2 = text2.Substring(0, text2.Length - ".dll.old".Length);
					}
					PluginRow item2 = new PluginRow
					{
						GUID = "(disabled)",
						Name = text2,
						Version = "-",
						Location = text,
						FileName = Path.GetFileName(text),
						Active = false,
						DisableNextBoot = true,
						Info = null,
						HarmonyIdCandidate = text2,
						Deps = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
					};
					list.Add(item2);
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)ex.Message);
			}
			plugins = list.OrderBy((PluginRow p) => (!p.Active) ? 1 : 0).ThenBy<PluginRow, string>((PluginRow p) => p.Name, StringComparer.InvariantCultureIgnoreCase).ToList();
		}

		private HashSet<string> ReadDeps(PluginInfo info)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
			try
			{
				Type type = (((Object)(object)info.Instance != (Object)null) ? ((object)info.Instance).GetType() : null);
				if (type != null)
				{
					object[] customAttributes = type.GetCustomAttributes(inherit: true);
					object[] array = customAttributes;
					foreach (object obj in array)
					{
						Type type2 = obj.GetType();
						string name = type2.Name;
						if (name.Contains("BepInDependency", StringComparison.InvariantCultureIgnoreCase))
						{
							PropertyInfo propertyInfo = type2.GetProperty("DependencyGUID") ?? type2.GetProperty("GUID");
							string text = ((propertyInfo != null) ? (propertyInfo.GetValue(obj) as string) : null);
							if (!string.IsNullOrEmpty(text))
							{
								hashSet.Add(text);
							}
						}
					}
				}
			}
			catch
			{
			}
			return hashSet;
		}

		private void BuildDuplicates()
		{
			duplicateDlls.Clear();
			try
			{
				string[] source = (Directory.Exists(Paths.PluginPath) ? Directory.GetFiles(Paths.PluginPath, "*.dll", SearchOption.AllDirectories) : Array.Empty<string>());
				IEnumerable<IGrouping<string, string>> enumerable = from g in source.GroupBy<string, string>((string p) => Path.GetFileName(p), StringComparer.InvariantCultureIgnoreCase)
					where g.Count() > 1
					select g;
				foreach (IGrouping<string, string> item in enumerable)
				{
					ConflictRow conflictRow = new ConflictRow
					{
						KeyFile = item.Key,
						Paths = item.ToList(),
						FileNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
					};
					foreach (string item2 in item)
					{
						conflictRow.FileNames.Add(Path.GetFileName(item2));
					}
					duplicateDlls.Add(conflictRow);
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)ex.Message);
			}
		}

		private void BuildPatchGraph()
		{
			overlaps.Clear();
			try
			{
				List<MethodBase> list = Harmony.GetAllPatchedMethods().ToList();
				foreach (MethodBase item2 in list)
				{
					HarmonyCompatUtil.PatchBundle patches = HarmonyCompatUtil.GetPatches(item2);
					if (patches == null)
					{
						continue;
					}
					List<string> list2 = patches.AllOwners.ToList();
					if (list2.Count == 0)
					{
						continue;
					}
					MethodOverlap methodOverlap = new MethodOverlap
					{
						Target = ((item2.DeclaringType != null) ? item2.DeclaringType.FullName : "?") + "::" + item2.Name,
						Owners = new List<OwnerCount>()
					};
					Dictionary<string, PatchCounts> dictionary = new Dictionary<string, PatchCounts>(StringComparer.InvariantCultureIgnoreCase);
					foreach (HarmonyCompatUtil.PatchRecord prefix in patches.Prefixes)
					{
						Inc(dictionary, prefix.Owner, 0);
					}
					foreach (HarmonyCompatUtil.PatchRecord postfix in patches.Postfixes)
					{
						Inc(dictionary, postfix.Owner, 1);
					}
					foreach (HarmonyCompatUtil.PatchRecord transpiler in patches.Transpilers)
					{
						Inc(dictionary, transpiler.Owner, 2);
					}
					foreach (HarmonyCompatUtil.PatchRecord finalizer in patches.Finalizers)
					{
						Inc(dictionary, finalizer.Owner, 3);
					}
					HashSet<string> hashSet = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
					foreach (string item3 in list2.Distinct<string>(StringComparer.InvariantCultureIgnoreCase))
					{
						PatchCounts counts = (dictionary.ContainsKey(item3) ? dictionary[item3] : default(PatchCounts));
						string display = ResolveOwnerDisplay(item3);
						methodOverlap.Owners.Add(new OwnerCount
						{
							MatchKey = item3,
							Display = display,
							Counts = counts
						});
						PluginRow pluginRow = FindPluginByOwnerKeyOrAlias(item3);
						string item = ((pluginRow != null) ? pluginRow.Location : ("owner:" + item3));
						hashSet.Add(item);
					}
					methodOverlap.OwnerIds = methodOverlap.Owners.Select((OwnerCount o) => o.MatchKey).ToHashSet<string>(StringComparer.InvariantCultureIgnoreCase);
					methodOverlap.GroupKeys = hashSet;
					overlaps.Add(methodOverlap);
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)ex.Message);
			}
		}

		private void BuildAnalysis()
		{
			analysis.Clear();
			try
			{
				List<MethodBase> list = Harmony.GetAllPatchedMethods().ToList();
				foreach (MethodBase item3 in list)
				{
					HarmonyCompatUtil.PatchBundle patches = HarmonyCompatUtil.GetPatches(item3);
					if (patches == null || patches.Prefixes.Count + patches.Postfixes.Count + patches.Transpilers.Count + patches.Finalizers.Count == 0)
					{
						continue;
					}
					AnalyzerRow analyzerRow = new AnalyzerRow();
					analyzerRow.Target = ((item3.DeclaringType != null) ? item3.DeclaringType.FullName : "?") + "::" + item3.Name;
					List<AnalyzerPatch> list2 = new List<AnalyzerPatch>();
					int count = patches.Prefixes.Count;
					int count2 = patches.Postfixes.Count;
					int count3 = patches.Transpilers.Count;
					int count4 = patches.Finalizers.Count;
					bool flag = false;
					bool flag2 = false;
					foreach (HarmonyCompatUtil.PatchRecord prefix in patches.Prefixes)
					{
						AnalyzerPatch analyzerPatch = new AnalyzerPatch();
						analyzerPatch.Owner = prefix.Owner;
						analyzerPatch.Display = ResolveOwnerDisplay(prefix.Owner);
						analyzerPatch.Kind = "Prefix";
						analyzerPatch.Priority = prefix.Priority;
						analyzerPatch.Before = prefix.Before ?? Array.Empty<string>();
						analyzerPatch.After = prefix.After ?? Array.Empty<string>();
						analyzerPatch.ReturnsBool = prefix.Method != null && prefix.Method.ReturnType == typeof(bool);
						analyzerPatch.HasRunOriginalParam = prefix.Method != null && HasRunOriginal(prefix.Method);
						AnalyzerPatch analyzerPatch2 = analyzerPatch;
						if (analyzerPatch2.ReturnsBool || analyzerPatch2.HasRunOriginalParam)
						{
							flag = true;
						}
						list2.Add(analyzerPatch2);
					}
					foreach (HarmonyCompatUtil.PatchRecord postfix in patches.Postfixes)
					{
						AnalyzerPatch analyzerPatch3 = new AnalyzerPatch
						{
							Owner = postfix.Owner,
							Display = ResolveOwnerDisplay(postfix.Owner),
							Kind = "Postfix",
							Priority = postfix.Priority,
							Before = (postfix.Before ?? Array.Empty<string>()),
							After = (postfix.After ?? Array.Empty<string>()),
							ModifiesResult = (postfix.Method != null && CanModifyResult(postfix.Method))
						};
						if (analyzerPatch3.ModifiesResult)
						{
							flag2 = true;
						}
						list2.Add(analyzerPatch3);
					}
					foreach (HarmonyCompatUtil.PatchRecord transpiler in patches.Transpilers)
					{
						AnalyzerPatch item = new AnalyzerPatch
						{
							Owner = transpiler.Owner,
							Display = ResolveOwnerDisplay(transpiler.Owner),
							Kind = "Transpiler",
							Priority = transpiler.Priority,
							Before = (transpiler.Before ?? Array.Empty<string>()),
							After = (transpiler.After ?? Array.Empty<string>())
						};
						list2.Add(item);
					}
					foreach (HarmonyCompatUtil.PatchRecord finalizer in patches.Finalizers)
					{
						AnalyzerPatch item2 = new AnalyzerPatch
						{
							Owner = finalizer.Owner,
							Display = ResolveOwnerDisplay(finalizer.Owner),
							Kind = "Finalizer",
							Priority = finalizer.Priority,
							Before = (finalizer.Before ?? Array.Empty<string>()),
							After = (finalizer.After ?? Array.Empty<string>())
						};
						list2.Add(item2);
					}
					string risk = "Low";
					string reason = "No control flow risks detected";
					if (count3 > 1)
					{
						risk = "High";
						reason = "Multiple transpilers rewriting IL";
					}
					else if (flag && count > 1)
					{
						risk = "High";
						reason = "Multiple prefixes may cancel or re-route original";
					}
					else if (count3 == 1 && (count > 0 || flag2))
					{
						risk = "Medium";
						reason = "Transpiler combined with other patches";
					}
					else if (count4 > 0)
					{
						risk = "Medium";
						reason = "Finalizer may alter exception handling";
					}
					else if (flag)
					{
						risk = "Medium";
						reason = "Prefix can skip original";
					}
					else if (flag2)
					{
						risk = "Low";
						reason = "Postfix may modify return value";
					}
					List<string> list3 = new List<string>();
					if (cfgExt.Value)
					{
						List<string> list4 = list2.Select((AnalyzerPatch p) => p.Owner).Distinct<string>(StringComparer.InvariantCultureIgnoreCase).ToList();
						Dictionary<string, HashSet<string>> dictionary = new Dictionary<string, HashSet<string>>(StringComparer.InvariantCultureIgnoreCase);
						foreach (string item4 in list4)
						{
							dictionary[item4] = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
						}
						List<(string, string)> list5 = new List<(string, string)>();
						foreach (AnalyzerPatch item5 in list2)
						{
							if (item5.Before != null)
							{
								string[] before = item5.Before;
								foreach (string text in before)
								{
									if (!string.IsNullOrWhiteSpace(text) && dictionary.ContainsKey(item5.Owner) && dictionary.ContainsKey(text))
									{
										dictionary[item5.Owner].Add(text);
									}
								}
							}
							if (item5.After == null)
							{
								continue;
							}
							string[] after = item5.After;
							foreach (string text2 in after)
							{
								if (!string.IsNullOrWhiteSpace(text2))
								{
									if (dictionary.ContainsKey(text2) && dictionary.ContainsKey(item5.Owner))
									{
										dictionary[text2].Add(item5.Owner);
									}
									list5.Add((item5.Owner, text2));
								}
							}
						}
						if (HasCycle(dictionary))
						{
							risk = "High";
							list3.Add("Ordering cycle detected between patches");
						}
						foreach (var item6 in list5)
						{
							PluginRow pluginRow = FindPluginByOwnerKeyOrAlias(item6.Item1);
							PluginRow pluginRow2 = FindPluginByOwnerKeyOrAlias(item6.Item2);
							if (pluginRow != null && pluginRow2 != null && !string.Equals(pluginRow.GUID, pluginRow2.GUID, StringComparison.InvariantCultureIgnoreCase) && !pluginRow.Deps.Contains(pluginRow2.GUID))
							{
								list3.Add(pluginRow.Name + " orders after " + pluginRow2.Name + " but has no BepInDependency");
							}
						}
					}
					if (cfgIL.Value && patches.Transpilers.Count > 1)
					{
						Dictionary<string, ILSig> dictionary2 = new Dictionary<string, ILSig>();
						foreach (HarmonyCompatUtil.PatchRecord transpiler2 in patches.Transpilers)
						{
							if (transpiler2.Method != null)
							{
								ILSig value = ILDiffUtil.BuildSig(transpiler2.Method);
								dictionary2[transpiler2.Owner] = value;
							}
						}
						List<string> list6 = dictionary2.Keys.ToList();
						for (int k = 0; k < list6.Count; k++)
						{
							for (int l = k + 1; l < list6.Count; l++)
							{
								string text3 = list6[k];
								string text4 = list6[l];
								int num = ILDiffUtil.Similarity(dictionary2[text3], dictionary2[text4]);
								if (num >= 50)
								{
									list3.Add($"Transpilers {text3} and {text4} share IL signature overlap {num}%");
								}
							}
						}
					}
					analyzerRow.Patches = (from p in list2
						orderby p.Kind, p.Priority descending
						select p).ToList();
					analyzerRow.Risk = risk;
					analyzerRow.Reason = reason;
					analyzerRow.Notes = list3;
					analysis.Add(analyzerRow);
				}
				analysis = (from a in analysis
					orderby (a.Risk == "High") ? 2 : ((a.Risk == "Medium") ? 1 : 0) descending, a.Target
					select a).ToList();
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)ex.Message);
			}
		}

		private void ApplyTracePatches()
		{
			try
			{
				List<MethodBase> methods = Harmony.GetAllPatchedMethods().ToList();
				TraceRuntime.Init(((BaseUnityPlugin)this).Info.Metadata.GUID + ".Trace");
				TraceRuntime.PatchAll(methods);
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)ex.Message);
			}
		}

		private static bool HasCycle(Dictionary<string, HashSet<string>> adj)
		{
			Dictionary<string, HashSet<string>> adj2 = adj;
			HashSet<string> visited = new HashSet<string>();
			HashSet<string> stack = new HashSet<string>();
			foreach (string key in adj2.Keys)
			{
				if (Dfs(key))
				{
					return true;
				}
			}
			return false;
			bool Dfs(string u)
			{
				if (stack.Contains(u))
				{
					return true;
				}
				if (visited.Contains(u))
				{
					return false;
				}
				visited.Add(u);
				stack.Add(u);
				if (adj2.TryGetValue(u, out HashSet<string> value))
				{
					foreach (string item in value)
					{
						if (Dfs(item))
						{
							return true;
						}
					}
				}
				stack.Remove(u);
				return false;
			}
		}

		private static bool HasRunOriginal(MethodInfo mi)
		{
			try
			{
				ParameterInfo[] parameters = mi.GetParameters();
				foreach (ParameterInfo parameterInfo in parameters)
				{
					if (parameterInfo.ParameterType.IsByRef && string.Equals(parameterInfo.ParameterType.GetElementType()?.FullName, "System.Boolean", StringComparison.InvariantCultureIgnoreCase) && string.Equals(parameterInfo.Name, "__runOriginal", StringComparison.InvariantCultureIgnoreCase))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool CanModifyResult(MethodInfo mi)
		{
			try
			{
				ParameterInfo[] parameters = mi.GetParameters();
				foreach (ParameterInfo parameterInfo in parameters)
				{
					if (parameterInfo.ParameterType.IsByRef && string.Equals(parameterInfo.Name, "__result", StringComparison.InvariantCultureIgnoreCase))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static void Inc(Dictionary<string, PatchCounts> map, string owner, int type)
		{
			if (string.IsNullOrEmpty(owner))
			{
				owner = "?";
			}
			if (!map.TryGetValue(owner, out var value))
			{
				value = default(PatchCounts);
			}
			switch (type)
			{
			case 0:
				value.Pre++;
				break;
			case 1:
				value.Post++;
				break;
			case 2:
				value.Trans++;
				break;
			default:
				value.Final++;
				break;
			}
			map[owner] = value;
		}

		private string ResolveOwnerDisplay(string owner)
		{
			string owner2 = owner;
			PluginRow pluginRow = FindPluginByOwnerKeyOrAlias(owner2);
			if (pluginRow != null)
			{
				return pluginRow.Name + " [" + pluginRow.GUID + "]";
			}
			PluginRow pluginRow2 = plugins.FirstOrDefault((PluginRow x) => x.Name.Equals(owner2, StringComparison.InvariantCultureIgnoreCase));
			if (pluginRow2 != null)
			{
				return pluginRow2.Name + " [" + pluginRow2.GUID + "]";
			}
			return owner2;
		}

		private PluginRow? FindPluginByOwnerKeyOrAlias(string owner)
		{
			string owner2 = owner;
			PluginRow pluginRow = plugins.FirstOrDefault((PluginRow x) => x.GUID.Equals(owner2, StringComparison.InvariantCultureIgnoreCase));
			if (pluginRow != null)
			{
				return pluginRow;
			}
			pluginRow = plugins.FirstOrDefault((PluginRow x) => x.HarmonyIdCandidate.Equals(owner2, StringComparison.InvariantCultureIgnoreCase));
			if (pluginRow != null)
			{
				return pluginRow;
			}
			pluginRow = plugins.FirstOrDefault((PluginRow x) => x.Name.Equals(owner2, StringComparison.InvariantCultureIgnoreCase));
			if (pluginRow != null)
			{
				return pluginRow;
			}
			PluginRow result = null;
			int num = -1;
			foreach (PluginRow plugin in plugins)
			{
				if (owner2.IndexOf(plugin.GUID, StringComparison.InvariantCultureIgnoreCase) >= 0)
				{
					int length = plugin.GUID.Length;
					if (length > num)
					{
						result = plugin;
						num = length;
					}
				}
				string text = San(owner2);
				string text2 = San(plugin.Name);
				if (!string.IsNullOrEmpty(text2) && text.Contains(text2))
				{
					int length2 = text2.Length;
					if (length2 > num)
					{
						result = plugin;
						num = length2;
					}
				}
			}
			return result;
		}

		private static string San(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(s.Length);
			foreach (char c in s)
			{
				if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}

		private void ToggleActive(PluginRow row)
		{
			try
			{
				if (row.Info != null && (Object)(object)row.Info.Instance != (Object)null)
				{
					((Behaviour)row.Info.Instance).enabled = row.Active;
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)ex.Message);
			}
		}

		private void DisableNowOrQueue(PluginRow row)
		{
			try
			{
				if (row.GUID == ((BaseUnityPlugin)this).Info.Metadata.GUID)
				{
					return;
				}
				string location = row.Location;
				if (location.EndsWith(".dll.old", StringComparison.InvariantCultureIgnoreCase))
				{
					return;
				}
				string text = location + ".dll.old";
				try
				{
					if (File.Exists(text))
					{
						File.Delete(text);
					}
					File.Move(location, text);
					row.Location = text;
					row.FileName = Path.GetFileName(text);
					row.Active = false;
				}
				catch (Exception ex)
				{
					Logger.LogWarning((object)ex.Message);
				}
			}
			catch (Exception ex2)
			{
				Logger.LogWarning((object)ex2.Message);
			}
		}

		private void TryRestore(PluginRow row)
		{
			try
			{
				string location = row.Location;
				if (!location.EndsWith(".dll.old", StringComparison.InvariantCultureIgnoreCase))
				{
					return;
				}
				string text = location.Substring(0, location.Length - 8);
				try
				{
					if (File.Exists(text))
					{
						File.Delete(text);
					}
					File.Move(location, text);
					row.Location = text;
					row.FileName = Path.GetFileName(text);
					row.DisableNextBoot = false;
				}
				catch (Exception ex)
				{
					Logger.LogWarning((object)ex.Message);
				}
			}
			catch (Exception ex2)
			{
				Logger.LogWarning((object)ex2.Message);
			}
		}

		private bool HasOverlapFor(PluginRow row)
		{
			string key = row.Location;
			return overlaps.Any((MethodOverlap x) => x.GroupCount > 1 && x.GroupKeys.Contains(key));
		}

		private void TakeCursor()
		{
			//IL_0011: 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 (_cursorTaken)
			{
				return;
			}
			_prevLock = Cursor.lockState;
			_prevVisible = Cursor.visible;
			Type type = FindTypeBySimpleName("CursorManager");
			object obj = type?.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null);
			if (obj != null)
			{
				try
				{
					type.GetMethod("Unlock", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(obj, new object[1] { 9999f });
				}
				catch
				{
				}
			}
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			_cursorTaken = true;
		}

		private void KeepCursorFree()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Cursor.lockState > 0)
			{
				Cursor.lockState = (CursorLockMode)0;
			}
			if (!Cursor.visible)
			{
				Cursor.visible = true;
			}
		}

		private void RestoreCursor()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (_cursorTaken)
			{
				Cursor.lockState = _prevLock;
				Cursor.visible = _prevVisible;
				_cursorTaken = false;
			}
		}

		private static Type? FindTypeBySimpleName(string simpleName)
		{
			string simpleName2 = simpleName;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type type = null;
				try
				{
					type = assembly.GetTypes().FirstOrDefault((Type x) => x.Name == simpleName2 || (x.FullName?.EndsWith("." + simpleName2) ?? false));
				}
				catch
				{
				}
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}
	}
}