Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Empress CompatibilityChecker v1.0.6
EmpressCompatChecker.dll
Decompiled 9 months agousing 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; } } }