Decompiled source of The Eye v2.3.2

plugins/WubarrksEye/WubarrksEye.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
using WubarrksEye.Core;
using WubarrksEye.Core.Commands;
using WubarrksEye.Core.Compat;
using WubarrksEye.Core.Dumpers;
using WubarrksEye.Core.Patches;
using WubarrksEye.Core.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
public static class DeepReflectionWalker
{
	private sealed class ReferenceEqualityComparer : IEqualityComparer<object>
	{
		public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer();

		public new bool Equals(object x, object y)
		{
			return x == y;
		}

		public int GetHashCode(object obj)
		{
			return RuntimeHelpers.GetHashCode(obj);
		}
	}

	private const int MAX_DEPTH = 32;

	private const int MAX_ITEMS = 500000;

	private static readonly HashSet<object> _visited = new HashSet<object>(ReferenceEqualityComparer.Instance);

	private static int _count;

	private static readonly string[] ForbiddenTypePrefixes = new string[35]
	{
		"PlayFab", "Steamworks", "UnityEngine.Networking", "UnityEngine.ResourceRequest", "UnityEngine.AsyncOperation", "System.Runtime.CompilerServices", "System.Threading", "System.Net", "System.IO", "System.Reflection.Emit",
		"System.Security", "System.Diagnostics", "System.Runtime.Remoting", "System.Runtime.InteropServices", "System.Runtime.Serialization", "System.Runtime.ExceptionServices", "System.Runtime.ConstrainedExecution", "System.Runtime.Versioning", "System.Runtime.Loader", "System.Runtime.GCSettings",
		"System.RuntimeType", "System.RuntimeTypeHandle", "System.RuntimeFieldHandle", "System.RuntimeMethodHandle", "System.RuntimeArgumentHandle", "System.RuntimeMethodInfoStub", "System.RuntimePropertyInfoStub", "System.RuntimeEventInfoStub", "System.RuntimeConstructorInfoStub", "System.RuntimeType+",
		"System.Runtime.CompilerServices.AsyncTaskMethodBuilder", "<>", "c__DisplayClass", "d__", "PrivateImplementationDetails"
	};

	public static void Walk(object root, Action<string, object> onField)
	{
		_visited.Clear();
		_count = 0;
		WalkInternal(root, "root", 0, onField);
	}

	private static void WalkInternal(object obj, string path, int depth, Action<string, object> onField)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		if (obj == null || depth > 32 || _count++ > 500000)
		{
			return;
		}
		Type type = obj.GetType();
		if (IsForbidden(type))
		{
			return;
		}
		Object val = (Object)((obj is Object) ? obj : null);
		if ((val != (Object)null && val == (Object)null) || !_visited.Add(obj))
		{
			return;
		}
		onField(path, obj);
		foreach (FieldInfo item in SafeFields(type))
		{
			try
			{
				object value = item.GetValue(obj);
				if (value != null)
				{
					string path2 = path + "." + item.Name;
					WalkInternal(value, path2, depth + 1, onField);
				}
			}
			catch
			{
			}
		}
		if (!(obj is IEnumerable enumerable) || obj is string)
		{
			return;
		}
		int num = 0;
		foreach (object item2 in enumerable)
		{
			if (item2 != null)
			{
				WalkInternal(item2, path + "[" + num + "]", depth + 1, onField);
				num++;
			}
		}
	}

	private static bool IsForbidden(Type t)
	{
		string text = t.FullName ?? t.Name;
		string[] forbiddenTypePrefixes = ForbiddenTypePrefixes;
		foreach (string value in forbiddenTypePrefixes)
		{
			if (text.StartsWith(value, StringComparison.Ordinal))
			{
				return true;
			}
		}
		return false;
	}

	private static IEnumerable<FieldInfo> SafeFields(Type t)
	{
		FieldInfo[] fields;
		try
		{
			fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}
		catch
		{
			yield break;
		}
		FieldInfo[] array = fields;
		FieldInfo[] array2 = array;
		foreach (FieldInfo fieldInfo in array2)
		{
			if (!fieldInfo.IsStatic && !fieldInfo.FieldType.IsPointer && !IsForbidden(fieldInfo.FieldType))
			{
				yield return fieldInfo;
			}
		}
	}
}
namespace WubarrksEye
{
	[BepInPlugin("wubarrk.theeye", "Wubarrk's Eye", "2.3.2")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "wubarrk.theeye";

		public const string PluginName = "Wubarrk's Eye";

		public const string PluginVersion = "2.3.2";

		private Harmony _harmony;

		private static ManualLogSource _log;

		public static ManualLogSource Log => _log;

		private void Awake()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			_log = ((BaseUnityPlugin)this).Logger;
			WubarrkLogger.Initialize(((BaseUnityPlugin)this).Logger);
			try
			{
				WubarrkConfig.Bind(((BaseUnityPlugin)this).Config);
				_log.LogInfo((object)"[Eye] WubarrkConfig bound.");
				_harmony = new Harmony("wubarrk.theeye");
				try
				{
					JObject val = GameShape.Probe();
					List<string> list = GameShape.Missing(val);
					int num = GameShape.MemberCount(val);
					if (list.Count == 0)
					{
						WubarrkLogger.Info(string.Format("[Eye.Compat] All {0} expected game members present. ZDO data via {1}.", num, val["ZdoDataStrategy"]));
					}
					else
					{
						WubarrkLogger.Warn(string.Format("[Eye.Compat] {0} of {1} expected game members MISSING on this build: {2}. ZDO data via {3}. A member with no fallback leaves its field out of the dump; see Manifest.json Compatibility.", list.Count, num, string.Join(", ", list), val["ZdoDataStrategy"]));
					}
					WubarrkLogger.Info("[Eye.Compat] Build shape: " + GameShape.ShapeSummary(val));
				}
				catch (Exception ex)
				{
					WubarrkLogger.Warn("[Eye.Compat] probe failed: " + ex.GetType().Name);
				}
				if (WubarrkConfig.ForceGlobalActiveArea.Value)
				{
					ApplyActiveAreaOverride();
				}
				else
				{
					WubarrkLogger.Info("[Eye] ZNetScene active-area override is OFF (config [ZDO] ForceGlobalActiveArea). ZDO dumps read ZDOMan directly.");
				}
				_harmony.PatchAll();
				WubarrkLogger.Info("[Eye] General Harmony patches applied.");
				EyeCommands.Initialize(((BaseUnityPlugin)this).Logger);
				GameObject val2 = new GameObject("EyeUIManager");
				val2.AddComponent<EyeUIManager>();
				val2.AddComponent<AutoDumpTrigger>();
				Object.DontDestroyOnLoad((Object)val2);
				_log.LogInfo((object)"[Eye] Plugin 2.3.2 initialization complete. Wubarrk's Eye is now watching.");
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"[Eye] Plugin initialization failed: {arg}");
			}
		}

		private void ApplyActiveAreaOverride()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			try
			{
				WubarrkLogger.Info("[Eye] Applying ZNetScene Area Overrides to force global ZDO existence...");
				HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(ZDOExistencePatch), "PrefixInActiveArea", (Type[])null, (Type[])null));
				HarmonyMethod val2 = new HarmonyMethod(AccessTools.Method(typeof(ZDOExistencePatch), "PrefixOutsideActiveArea", (Type[])null, (Type[])null));
				int num = 0;
				MethodInfo[] methods = typeof(ZNetScene).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if ((!(methodInfo.Name != "InActiveArea") || !(methodInfo.Name != "OutsideActiveArea")) && !(methodInfo.ReturnType != typeof(bool)))
					{
						_harmony.Patch((MethodBase)methodInfo, (methodInfo.Name == "InActiveArea") ? val : val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						num++;
					}
				}
				if (num == 0)
				{
					throw new Exception("No ZNetScene.InActiveArea / OutsideActiveArea overloads found.");
				}
				WubarrkLogger.Info($"[Eye] <color=#00FF00>ZNetScene Area Overrides applied to {num} overloads. Every ZDO in the world will be instantiated this session.</color>");
			}
			catch (Exception ex)
			{
				WubarrkLogger.Error("[Eye] FAILED to apply ZNetScene Area Overrides. Exception: " + ex.Message);
				WubarrkLogger.Warn("[Eye] IMPACT: scene/prefab instantiation stays vanilla. ZDO dumps are unaffected. Game will continue to load normally.");
			}
		}

		private void OnDestroy()
		{
			try
			{
				if (_harmony != null)
				{
					_harmony.UnpatchSelf();
					_log.LogInfo((object)"[Eye] Harmony patches unpatched on destroy.");
				}
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"[Eye] Failed during OnDestroy: {arg}");
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "WubarrksEye";

		public const string PLUGIN_NAME = "WubarrksEye";

		public const string PLUGIN_VERSION = "2.3.2";
	}
}
namespace WubarrksEye.HarmonyPatches
{
	internal static class HarmonyBootstrap
	{
		public static void ApplyAll(Harmony harmony)
		{
			if (harmony == null)
			{
				throw new ArgumentNullException("harmony");
			}
			try
			{
				Assembly assembly = typeof(HarmonyBootstrap).Assembly;
				WubarrkLogger.Info("[HarmonyBootstrap] Running PatchAllSafe for attribute-based patches...");
				HarmonyPatcher.PatchAllSafe(harmony, assembly);
				int num = harmony.GetPatchedMethods().Count();
				WubarrkLogger.Info($"[HarmonyBootstrap] Total patched methods after bootstrap: {num}");
			}
			catch (Exception arg)
			{
				WubarrkLogger.Warn($"[HarmonyBootstrap] Fatal error while applying patches: {arg}");
			}
		}
	}
	internal static class HarmonyPatcher
	{
		public static int PatchAllOverloads(Harmony harmony, Type targetType, string methodName, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null)
		{
			if (harmony == null)
			{
				throw new ArgumentNullException("harmony");
			}
			if (targetType == null)
			{
				throw new ArgumentNullException("targetType");
			}
			if (string.IsNullOrEmpty(methodName))
			{
				throw new ArgumentNullException("methodName");
			}
			MethodInfo[] array;
			try
			{
				array = (from m in targetType.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
					where string.Equals(m.Name, methodName, StringComparison.Ordinal)
					select m).ToArray();
			}
			catch (Exception ex)
			{
				LoggerWarning("PatchAllOverloads: failed to enumerate methods on " + targetType.FullName + ": " + ex.Message);
				return 0;
			}
			if (array.Length == 0)
			{
				array = FindSimilarNamedMethods(targetType, methodName).ToArray();
				if (array.Length == 0)
				{
					LoggerDebug("PatchAllOverloads: no methods named or similar to '" + methodName + "' found on " + targetType.FullName + ".");
					return 0;
				}
				LoggerWarning("PatchAllOverloads: exact method '" + methodName + "' not found on " + targetType.FullName + ". " + string.Format("Using {0} similar method(s): {1}", array.Length, string.Join(", ", array.Select((MethodInfo m) => m.Name))));
			}
			int num = 0;
			MethodInfo[] array2 = array;
			foreach (MethodInfo methodInfo in array2)
			{
				if (!IsPatchable(methodInfo))
				{
					LoggerDebug("PatchAllOverloads: skipping non-patchable " + targetType.FullName + "." + methodInfo.Name + "(" + ParamTypes(methodInfo) + ")");
					continue;
				}
				try
				{
					harmony.Patch((MethodBase)methodInfo, prefix, postfix, transpiler, (HarmonyMethod)null, (HarmonyMethod)null);
					num++;
					LoggerInfo("Patched " + targetType.FullName + "." + methodInfo.Name + "(" + ParamTypes(methodInfo) + ")");
				}
				catch (Exception ex2)
				{
					LoggerWarning("PatchAllOverloads: failed to patch " + targetType.FullName + "." + methodInfo.Name + "(" + ParamTypes(methodInfo) + "): " + ex2.Message);
				}
			}
			return num;
		}

		public static bool PatchSpecificOverload(Harmony harmony, Type targetType, string methodName, Type[] parameterTypes, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null)
		{
			if (harmony == null)
			{
				throw new ArgumentNullException("harmony");
			}
			if (targetType == null)
			{
				throw new ArgumentNullException("targetType");
			}
			if (string.IsNullOrEmpty(methodName))
			{
				throw new ArgumentNullException("methodName");
			}
			parameterTypes = parameterTypes ?? Type.EmptyTypes;
			MethodInfo methodInfo = null;
			try
			{
				methodInfo = targetType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null);
			}
			catch (AmbiguousMatchException)
			{
				LoggerWarning("PatchSpecificOverload: ambiguous match for " + targetType.FullName + "." + methodName + "(" + string.Join(", ", parameterTypes.Select((Type t) => t?.Name ?? "null")) + "). Consider PatchAllOverloads.");
				return false;
			}
			catch (Exception ex2)
			{
				LoggerWarning("PatchSpecificOverload: error resolving " + targetType.FullName + "." + methodName + ": " + ex2.Message);
				return false;
			}
			if (methodInfo == null)
			{
				methodInfo = FindMethodBySignatureShape(targetType, methodName, parameterTypes);
				if (methodInfo == null)
				{
					LoggerDebug("PatchSpecificOverload: method not found " + targetType.FullName + "." + methodName + "(" + string.Join(", ", parameterTypes.Select((Type t) => t?.Name ?? "null")) + ").");
					return false;
				}
				LoggerWarning("PatchSpecificOverload: using fallback method " + targetType.FullName + "." + methodInfo.Name + "(" + ParamTypes(methodInfo) + ") instead of missing " + methodName + ".");
			}
			if (!IsPatchable(methodInfo))
			{
				LoggerWarning("PatchSpecificOverload: method " + targetType.FullName + "." + methodInfo.Name + "(" + ParamTypes(methodInfo) + ") is not patchable (abstract/extern/no body).");
				return false;
			}
			try
			{
				harmony.Patch((MethodBase)methodInfo, prefix, postfix, transpiler, (HarmonyMethod)null, (HarmonyMethod)null);
				LoggerInfo("Patched specific overload " + targetType.FullName + "." + methodInfo.Name + "(" + ParamTypes(methodInfo) + ")");
				return true;
			}
			catch (Exception ex3)
			{
				LoggerWarning("PatchSpecificOverload: failed to patch " + targetType.FullName + "." + methodInfo.Name + "(" + ParamTypes(methodInfo) + "): " + ex3.Message);
				return false;
			}
		}

		public static int SafePatchMethods(Harmony harmony, IEnumerable<MethodBase> methods, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null)
		{
			if (harmony == null)
			{
				throw new ArgumentNullException("harmony");
			}
			if (methods == null)
			{
				throw new ArgumentNullException("methods");
			}
			int num = 0;
			foreach (MethodBase method in methods)
			{
				if (method == null)
				{
					continue;
				}
				if (!IsPatchable(method))
				{
					LoggerDebug("SafePatchMethods: skipping non-patchable " + method.DeclaringType?.FullName + "." + method.Name + "(" + ParamTypes(method) + ")");
					continue;
				}
				try
				{
					harmony.Patch(method, prefix, postfix, transpiler, (HarmonyMethod)null, (HarmonyMethod)null);
					num++;
					LoggerInfo("Patched " + method.DeclaringType?.FullName + "." + method.Name + "(" + ParamTypes(method) + ")");
				}
				catch (Exception ex)
				{
					LoggerWarning("SafePatchMethods: failed to patch " + method.DeclaringType?.FullName + "." + method.Name + "(" + ParamTypes(method) + "): " + ex.Message);
				}
			}
			return num;
		}

		public static void PatchAllSafe(Harmony harmony, Assembly assembly)
		{
			if (harmony == null)
			{
				throw new ArgumentNullException("harmony");
			}
			if (assembly == null)
			{
				throw new ArgumentNullException("assembly");
			}
			Type[] array;
			try
			{
				array = assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				array = ex.Types.Where((Type t) => t != null).ToArray();
			}
			catch (Exception ex2)
			{
				LoggerWarning("PatchAllSafe: failed to enumerate types in assembly: " + ex2.Message);
				return;
			}
			int num = 0;
			Type[] array2 = array;
			foreach (Type type in array2)
			{
				if (type == null || !type.IsClass)
				{
					continue;
				}
				object[] array3 = type.GetCustomAttributes(inherit: false).Where(delegate(object a)
				{
					string fullName = a.GetType().FullName;
					return (fullName != null && fullName.StartsWith("HarmonyLib.HarmonyPatch")) || (a.GetType().FullName?.Contains("HarmonyPatch") ?? false);
				}).ToArray();
				if (array3.Length != 0)
				{
					try
					{
						int num3 = SafePatchClass(harmony, type, array3);
						num += num3;
					}
					catch (Exception ex3)
					{
						LoggerWarning("PatchAllSafe: error processing patch class " + type.FullName + ": " + ex3.Message);
					}
				}
			}
			LoggerInfo($"PatchAllSafe: completed. Total patched methods: {num}");
		}

		private static int SafePatchClass(Harmony harmony, Type patchClass, object[] patchAttrs)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (harmony == null)
			{
				throw new ArgumentNullException("harmony");
			}
			if (patchClass == null)
			{
				throw new ArgumentNullException("patchClass");
			}
			int patchedCount = 0;
			if (patchAttrs.Any((object a) => a.GetType().Name == "HarmonyPatchAllAttribute"))
			{
				LoggerDebug("SafePatchClass: skipping HarmonyPatchAll on " + patchClass.FullName + " (too broad).");
				return 0;
			}
			object[] array = patchAttrs.Where((object a) => a.GetType().Name == "HarmonyPatchAttribute").ToArray();
			if (array.Length == 0)
			{
				try
				{
					new PatchClassProcessor(harmony, patchClass).Patch();
					LoggerInfo("SafePatchClass: PatchClassProcessor applied for " + patchClass.FullName + ".");
					return 1;
				}
				catch (Exception ex)
				{
					LoggerWarning("SafePatchClass: PatchClassProcessor failed for " + patchClass.FullName + ": " + ex.Message);
					return 0;
				}
			}
			object[] array2 = array;
			foreach (object attr in array2)
			{
				try
				{
					if (!TryProcessHarmonyPatchAttribute(harmony, patchClass, attr, ref patchedCount))
					{
						LoggerDebug("SafePatchClass: HarmonyPatch on " + patchClass.FullName + " could not be resolved; skipped.");
					}
				}
				catch (Exception ex2)
				{
					LoggerWarning("SafePatchClass: error processing HarmonyPatch attribute on " + patchClass.FullName + ": " + ex2.Message);
				}
			}
			return patchedCount;
		}

		private static bool TryProcessHarmonyPatchAttribute(Harmony harmony, Type patchClass, object attr, ref int patchedCount)
		{
			Type type = attr.GetType();
			PropertyInfo propertyInfo = type.GetProperty("info") ?? type.GetProperty("Info");
			if (propertyInfo != null)
			{
				object value = propertyInfo.GetValue(attr);
				if (value != null)
				{
					return ProcessHarmonyPatchInfo(harmony, patchClass, value, ref patchedCount);
				}
			}
			FieldInfo? obj = type.GetField("declaringType") ?? type.GetField("DeclaringType");
			FieldInfo fieldInfo = type.GetField("methodName") ?? type.GetField("MethodName");
			FieldInfo fieldInfo2 = type.GetField("argumentTypes") ?? type.GetField("ArgumentTypes");
			Type type2 = obj?.GetValue(attr) as Type;
			string text = fieldInfo?.GetValue(attr) as string;
			Type[] argTypes = fieldInfo2?.GetValue(attr) as Type[];
			if (type2 == null || string.IsNullOrEmpty(text))
			{
				return false;
			}
			return ProcessTargetSpec(harmony, patchClass, type2, text, argTypes, ref patchedCount);
		}

		private static bool ProcessHarmonyPatchInfo(Harmony harmony, Type patchClass, object info, ref int patchedCount)
		{
			Type type = info.GetType();
			PropertyInfo propertyInfo = type.GetProperty("declaringType") ?? type.GetProperty("DeclaringType");
			PropertyInfo propertyInfo2 = type.GetProperty("methodName") ?? type.GetProperty("MethodName");
			PropertyInfo propertyInfo3 = type.GetProperty("argumentTypes") ?? type.GetProperty("ArgumentTypes");
			Type type2 = null;
			string text = null;
			Type[] argTypes = null;
			if (propertyInfo != null)
			{
				type2 = propertyInfo.GetValue(info) as Type;
			}
			if (propertyInfo2 != null)
			{
				text = propertyInfo2.GetValue(info) as string;
			}
			if (propertyInfo3 != null)
			{
				argTypes = propertyInfo3.GetValue(info) as Type[];
			}
			if (type2 == null || string.IsNullOrEmpty(text))
			{
				return false;
			}
			return ProcessTargetSpec(harmony, patchClass, type2, text, argTypes, ref patchedCount);
		}

		private static bool ProcessTargetSpec(Harmony harmony, Type patchClass, Type targetType, string methodName, Type[] argTypes, ref int patchedCount)
		{
			HarmonyMethod harmonyMethodFromPatchClass = GetHarmonyMethodFromPatchClass(patchClass, "Prefix");
			HarmonyMethod harmonyMethodFromPatchClass2 = GetHarmonyMethodFromPatchClass(patchClass, "Postfix");
			HarmonyMethod harmonyMethodFromPatchClass3 = GetHarmonyMethodFromPatchClass(patchClass, "Transpiler");
			if (argTypes != null && argTypes.Length != 0)
			{
				MethodInfo methodInfo = null;
				try
				{
					methodInfo = targetType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, argTypes, null);
				}
				catch (AmbiguousMatchException)
				{
					LoggerWarning("SafePatchClass: ambiguous match for " + targetType.FullName + "." + methodName + " with specified args; attempting signature-shape fallback.");
				}
				if (methodInfo == null)
				{
					methodInfo = FindMethodBySignatureShape(targetType, methodName, argTypes);
				}
				if (methodInfo == null)
				{
					LoggerDebug("SafePatchClass: method not found " + targetType.FullName + "." + methodName + "(" + string.Join(", ", argTypes.Select((Type t) => t?.Name ?? "null")) + ").");
					return false;
				}
				if (!IsPatchable(methodInfo))
				{
					LoggerDebug("SafePatchClass: target not patchable " + targetType.FullName + "." + methodInfo.Name + "(" + ParamTypes(methodInfo) + "); skipping.");
					return false;
				}
				try
				{
					harmony.Patch((MethodBase)methodInfo, harmonyMethodFromPatchClass, harmonyMethodFromPatchClass2, harmonyMethodFromPatchClass3, (HarmonyMethod)null, (HarmonyMethod)null);
					patchedCount++;
					LoggerInfo("SafePatchClass: patched " + targetType.FullName + "." + methodInfo.Name + "(" + ParamTypes(methodInfo) + ") via " + patchClass.FullName);
					return true;
				}
				catch (Exception ex2)
				{
					LoggerWarning("SafePatchClass: failed to patch " + targetType.FullName + "." + methodInfo.Name + ": " + ex2.Message);
					return false;
				}
			}
			int num = PatchAllOverloads(harmony, targetType, methodName, harmonyMethodFromPatchClass, harmonyMethodFromPatchClass2, harmonyMethodFromPatchClass3);
			patchedCount += num;
			return num > 0;
		}

		private static HarmonyMethod GetHarmonyMethodFromPatchClass(Type patchClass, string methodName)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			try
			{
				MethodInfo method = patchClass.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					return null;
				}
				return new HarmonyMethod(method);
			}
			catch
			{
				return null;
			}
		}

		public static bool IsPatchable(MethodBase method)
		{
			if (method == null)
			{
				return false;
			}
			if (method.IsAbstract)
			{
				return false;
			}
			if ((method.Attributes & MethodAttributes.PinvokeImpl) != MethodAttributes.PrivateScope)
			{
				return false;
			}
			MethodInfo methodInfo = method as MethodInfo;
			if (methodInfo != null)
			{
				try
				{
					if (methodInfo.GetMethodBody() == null)
					{
						return false;
					}
				}
				catch
				{
					return false;
				}
			}
			return true;
		}

		private static string ParamTypes(MethodBase m)
		{
			try
			{
				return string.Join(", ", from p in m.GetParameters()
					select p.ParameterType.Name);
			}
			catch
			{
				return "";
			}
		}

		private static void LoggerInfo(string msg)
		{
			try
			{
				WubarrkLogger.Info("[HarmonyPatcher] " + msg);
			}
			catch
			{
			}
		}

		private static void LoggerWarning(string msg)
		{
			try
			{
				WubarrkLogger.Warn("[HarmonyPatcher] " + msg);
			}
			catch
			{
			}
		}

		private static void LoggerDebug(string msg)
		{
			try
			{
				WubarrkLogger.Info("[HarmonyPatcher][Debug] " + msg);
			}
			catch
			{
			}
		}

		private static IEnumerable<MethodInfo> FindSimilarNamedMethods(Type type, string methodName)
		{
			MethodInfo[] methods;
			try
			{
				methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			}
			catch
			{
				yield break;
			}
			string target = methodName.ToLowerInvariant();
			MethodInfo[] array = methods;
			MethodInfo[] array2 = array;
			foreach (MethodInfo methodInfo in array2)
			{
				string text = methodInfo.Name.ToLowerInvariant();
				if (!(text == target) && (text.Contains(target) || target.Contains(text) || LevenshteinDistance(text, target) <= 2))
				{
					yield return methodInfo;
				}
			}
		}

		private static MethodInfo FindMethodBySignatureShape(Type type, string originalName, Type[] parameterTypes)
		{
			MethodInfo[] methods;
			try
			{
				methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			}
			catch
			{
				return null;
			}
			string target = originalName.ToLowerInvariant();
			MethodInfo methodInfo = (from m in methods
				where ParametersMatchExactly(m, parameterTypes)
				orderby LevenshteinDistance(m.Name.ToLowerInvariant(), target)
				select m).FirstOrDefault();
			if (methodInfo != null)
			{
				return methodInfo;
			}
			return (from m in methods
				where m.GetParameters().Length == parameterTypes.Length
				orderby LevenshteinDistance(m.Name.ToLowerInvariant(), target)
				select m).FirstOrDefault();
		}

		private static bool ParametersMatchExactly(MethodBase m, Type[] parameterTypes)
		{
			ParameterInfo[] parameters = m.GetParameters();
			if (parameters.Length != parameterTypes.Length)
			{
				return false;
			}
			for (int i = 0; i < parameters.Length; i++)
			{
				if (parameters[i].ParameterType != parameterTypes[i])
				{
					return false;
				}
			}
			return true;
		}

		private static int LevenshteinDistance(string a, string b)
		{
			if (string.IsNullOrEmpty(a))
			{
				return b?.Length ?? 0;
			}
			if (string.IsNullOrEmpty(b))
			{
				return a.Length;
			}
			int[,] array = new int[a.Length + 1, b.Length + 1];
			for (int i = 0; i <= a.Length; i++)
			{
				array[i, 0] = i;
			}
			for (int j = 0; j <= b.Length; j++)
			{
				array[0, j] = j;
			}
			for (int k = 1; k <= a.Length; k++)
			{
				for (int l = 1; l <= b.Length; l++)
				{
					int num = ((a[k - 1] != b[l - 1]) ? 1 : 0);
					array[k, l] = Math.Min(Math.Min(array[k - 1, l] + 1, array[k, l - 1] + 1), array[k - 1, l - 1] + num);
				}
			}
			return array[a.Length, b.Length];
		}
	}
}
namespace WubarrksEye.Core
{
	internal static class ApiDumpWriter
	{
		public static void WriteTypeApi(TextWriter w, Type type)
		{
			if (type == null)
			{
				return;
			}
			AssemblyName name = type.Assembly.GetName();
			w.WriteLine("=== API BEGIN ===");
			w.WriteLine("Type: " + type.FullName);
			w.WriteLine("Namespace: " + (type.Namespace ?? "<none>"));
			w.WriteLine("Assembly: " + name.Name);
			w.WriteLine($"AssemblyVersion: {name.Version}");
			w.WriteLine("Kind: " + GetTypeKind(type));
			w.WriteLine($"IsAbstract: {type.IsAbstract}");
			w.WriteLine($"IsSealed: {type.IsSealed}");
			w.WriteLine($"IsGenericType: {type.IsGenericType}");
			Type[] array = (type.IsGenericType ? type.GetGenericArguments() : Type.EmptyTypes);
			w.WriteLine("GenericArguments:");
			if (array.Length == 0)
			{
				w.WriteLine("<none>");
			}
			else
			{
				Type[] array2 = array;
				foreach (Type type2 in array2)
				{
					w.WriteLine(type2.FullName ?? type2.Name);
				}
			}
			w.WriteLine("InheritanceChain:");
			foreach (Type item in GetInheritanceChain(type))
			{
				w.WriteLine(item.FullName ?? item.Name);
			}
			w.WriteLine("Implements:");
			Type[] interfaces = type.GetInterfaces();
			if (interfaces.Length == 0)
			{
				w.WriteLine("<none>");
			}
			else
			{
				foreach (Type item2 in interfaces.OrderBy((Type type3) => type3.FullName))
				{
					w.WriteLine(item2.FullName);
				}
			}
			w.WriteLine("Attributes:");
			List<string> list = SafeGetCustomAttributes(type);
			if (list.Count == 0)
			{
				w.WriteLine("<none>");
			}
			else
			{
				foreach (string item3 in list)
				{
					w.WriteLine(item3);
				}
			}
			w.WriteLine("EnumValues:");
			if (type.IsEnum)
			{
				string[] names = Enum.GetNames(type);
				Array values = Enum.GetValues(type);
				for (int num = 0; num < names.Length; num++)
				{
					w.WriteLine($"{names[num]} = {(int)values.GetValue(num)}");
				}
			}
			else
			{
				w.WriteLine("<none>");
			}
			w.WriteLine("Fields:");
			FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (fields.Length == 0)
			{
				w.WriteLine("<none>");
			}
			else
			{
				foreach (FieldInfo item4 in fields.OrderBy((FieldInfo f) => f.Name))
				{
					w.WriteLine(item4.FieldType.FullName + " " + item4.Name + " " + GetFieldModifiers(item4));
				}
			}
			w.WriteLine("Properties:");
			PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (properties.Length == 0)
			{
				w.WriteLine("<none>");
			}
			else
			{
				foreach (PropertyInfo item5 in properties.OrderBy((PropertyInfo p) => p.Name))
				{
					w.WriteLine(item5.PropertyType.FullName + " " + item5.Name + " " + GetPropertyModifiers(item5) + " " + GetPropertyAccessorFlags(item5));
				}
			}
			w.WriteLine("Events:");
			EventInfo[] events = type.GetEvents(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (events.Length == 0)
			{
				w.WriteLine("<none>");
			}
			else
			{
				foreach (EventInfo item6 in events.OrderBy((EventInfo e) => e.Name))
				{
					w.WriteLine(item6.EventHandlerType.FullName + " " + item6.Name + " " + GetMethodModifiers(item6.GetAddMethod(nonPublic: true)));
				}
			}
			w.WriteLine("Methods:");
			MethodInfo[] array3 = (from methodInfo in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
				where !methodInfo.IsSpecialName
				orderby methodInfo.Name, methodInfo.GetParameters().Length
				select methodInfo).ToArray();
			if (array3.Length == 0)
			{
				w.WriteLine("<none>");
			}
			else
			{
				MethodInfo[] array4 = array3;
				foreach (MethodInfo m in array4)
				{
					w.WriteLine(FormatFullMethodSignature(m));
				}
			}
			w.WriteLine("UnityMetadata:");
			w.WriteLine($"IsMonoBehaviour: {typeof(MonoBehaviour).IsAssignableFrom(type)}");
			w.WriteLine($"IsScriptableObject: {typeof(ScriptableObject).IsAssignableFrom(type)}");
			w.WriteLine("RequiredComponents:");
			RequireComponent[] array5 = type.GetCustomAttributes(inherit: true).OfType<RequireComponent>().ToArray();
			if (array5.Length == 0)
			{
				w.WriteLine("<none>");
			}
			else
			{
				RequireComponent[] array6 = array5;
				foreach (RequireComponent val in array6)
				{
					if (val.m_Type0 != null)
					{
						w.WriteLine(val.m_Type0.FullName);
					}
					if (val.m_Type1 != null)
					{
						w.WriteLine(val.m_Type1.FullName);
					}
					if (val.m_Type2 != null)
					{
						w.WriteLine(val.m_Type2.FullName);
					}
				}
			}
			w.WriteLine("=== API END ===");
		}

		internal static string GetTypeKind(Type t)
		{
			if (t.IsInterface)
			{
				return "interface";
			}
			if (t.IsEnum)
			{
				return "enum";
			}
			if (t.IsValueType)
			{
				return "struct";
			}
			return "class";
		}

		internal static IEnumerable<Type> GetInheritanceChain(Type t)
		{
			while (t != null)
			{
				yield return t;
				t = t.BaseType;
			}
		}

		internal static List<string> SafeGetCustomAttributes(MemberInfo m)
		{
			try
			{
				return (from a in m.GetCustomAttributes(inherit: true)
					select a.GetType().FullName).ToList();
			}
			catch
			{
				return new List<string>();
			}
		}

		internal static string GetFieldModifiers(FieldInfo f)
		{
			List<string> list = new List<string>();
			list.Add("[" + (f.IsPublic ? "public" : (f.IsFamily ? "protected" : (f.IsAssembly ? "internal" : (f.IsPrivate ? "private" : "unknown")))));
			if (f.IsStatic)
			{
				list.Add("static");
			}
			if (f.IsInitOnly)
			{
				list.Add("readonly");
			}
			if (f.IsLiteral && !f.IsInitOnly)
			{
				list.Add("const");
			}
			list.Add("]");
			return string.Join(" ", list);
		}

		internal static string GetPropertyModifiers(PropertyInfo p)
		{
			MethodInfo methodInfo = p.GetGetMethod(nonPublic: true) ?? p.GetSetMethod(nonPublic: true);
			if (!(methodInfo != null))
			{
				return "";
			}
			return GetMethodModifiers(methodInfo);
		}

		internal static string GetPropertyAccessorFlags(PropertyInfo p)
		{
			MethodInfo getMethod = p.GetGetMethod(nonPublic: true);
			MethodInfo setMethod = p.GetSetMethod(nonPublic: true);
			if (getMethod == null && setMethod == null)
			{
				return "";
			}
			List<string> list = new List<string>();
			if (getMethod != null)
			{
				list.Add(GetVisibility(getMethod) + " get");
			}
			if (setMethod != null)
			{
				list.Add(GetVisibility(setMethod) + " set");
			}
			return "{" + string.Join(", ", list) + "}";
		}

		internal static string GetVisibility(MethodBase m)
		{
			if (m.IsPublic)
			{
				return "public";
			}
			if (m.IsFamily)
			{
				return "protected";
			}
			if (m.IsAssembly)
			{
				return "internal";
			}
			if (m.IsPrivate)
			{
				return "private";
			}
			return "unknown";
		}

		internal static string GetMethodModifiers(MethodBase m)
		{
			List<string> list = new List<string>();
			list.Add("[" + GetVisibility(m));
			if (m.IsStatic)
			{
				list.Add("static");
			}
			if (m is MethodInfo methodInfo)
			{
				if (methodInfo.IsAbstract)
				{
					list.Add("abstract");
				}
				else if (methodInfo.IsVirtual && methodInfo.GetBaseDefinition() != methodInfo && !methodInfo.IsFinal)
				{
					list.Add("override");
				}
				else if (methodInfo.IsVirtual && !methodInfo.IsAbstract && !methodInfo.IsFinal)
				{
					list.Add("virtual");
				}
			}
			list.Add("]");
			return string.Join(" ", list);
		}

		internal static string FormatFullMethodSignature(MethodInfo m)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(GetMethodModifiers(m));
			stringBuilder.Append(' ');
			stringBuilder.Append(m.ReturnType.FullName);
			stringBuilder.Append(' ');
			stringBuilder.Append(m.Name);
			if (m.IsGenericMethod)
			{
				Type[] genericArguments = m.GetGenericArguments();
				stringBuilder.Append('<');
				stringBuilder.Append(string.Join(", ", genericArguments.Select((Type a) => a.FullName ?? a.Name)));
				stringBuilder.Append('>');
			}
			stringBuilder.Append('(');
			ParameterInfo[] parameters = m.GetParameters();
			for (int num = 0; num < parameters.Length; num++)
			{
				if (num > 0)
				{
					stringBuilder.Append(", ");
				}
				ParameterInfo parameterInfo = parameters[num];
				if (parameterInfo.IsOut)
				{
					stringBuilder.Append("out ");
				}
				else if (parameterInfo.ParameterType.IsByRef)
				{
					stringBuilder.Append("ref ");
				}
				stringBuilder.Append(parameterInfo.ParameterType.FullName ?? parameterInfo.ParameterType.Name);
				stringBuilder.Append(' ');
				stringBuilder.Append(parameterInfo.Name);
			}
			stringBuilder.Append(')');
			return stringBuilder.ToString();
		}
	}
	internal static class EyeCommands
	{
		private static ManualLogSource _logger;

		public static void Initialize(ManualLogSource logger)
		{
			_logger = logger ?? throw new ArgumentNullException("logger");
			RegisterCommand("dump_eye", "Wubarrk's Eye: full dump. Options: baseline=<dir> (Huginn baseline), scan=<plugin dir> (ModImpact), nodiff, noml, nozdo, noscene, noloc, noimpact", DumpEye);
			RegisterCommand("eye_status", "Wubarrk's Eye: show dump progress and the last output folder", Status);
			_logger.LogInfo((object)"[Eye/Commands] EyeCommands initialized.");
		}

		private static void RegisterCommand(string name, string description, Action<string[]> handler)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				new ConsoleCommand(name, description, (ConsoleEvent)delegate(ConsoleEventArgs args)
				{
					handler(args.Args);
				}, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				_logger.LogInfo((object)("[Eye/Commands] Registered command: " + name));
			}
			catch (Exception arg)
			{
				_logger.LogError((object)$"[Eye/Commands] Failed to register command '{name}': {arg}");
			}
		}

		private static void Say(string text)
		{
			try
			{
				_logger.LogInfo((object)("[Eye/Commands] " + text));
			}
			catch
			{
			}
			try
			{
				Console instance = Console.instance;
				if (instance != null)
				{
					instance.Print("[Eye] " + text);
				}
			}
			catch
			{
			}
		}

		private static void DumpEye(string[] args)
		{
			try
			{
				if (DumpManager.IsRunning)
				{
					Say($"A dump is already running ({DumpManager.CurrentPhase}, {DumpManager.OverallProgress:F0}%).");
					return;
				}
				DumpManager.DumpOptions options = DumpManager.DumpOptions.Everything();
				for (int i = 1; i < args.Length; i++)
				{
					string text = args[i];
					if (string.IsNullOrEmpty(text))
					{
						continue;
					}
					string text2 = text.ToLowerInvariant();
					if (text2.StartsWith("baseline="))
					{
						options.BaselineDir = text.Substring("baseline=".Length).Trim(new char[1] { '"' });
						continue;
					}
					switch (text2)
					{
					case "nodiff":
						options.RunHuginnsReport = false;
						continue;
					case "noml":
						options.DumpAgentML = false;
						continue;
					case "nozdo":
						options.DumpZDOs = false;
						continue;
					case "noscene":
						options.DumpScene = false;
						continue;
					case "noloc":
						WubarrkConfig.DumpLocalization.Value = false;
						continue;
					case "noimpact":
						options.DumpModImpact = false;
						continue;
					}
					if (text2.StartsWith("scan="))
					{
						options.ScanPluginDirs = text.Substring("scan=".Length).Trim(new char[1] { '"' });
					}
					else
					{
						Say("Unknown option '" + text + "' ignored. Options: baseline=<dir> scan=<dir> nodiff noml nozdo noscene noloc noimpact");
					}
				}
				if (!string.IsNullOrEmpty(options.BaselineDir) && !Directory.Exists(options.BaselineDir))
				{
					Say("Baseline directory not found: " + options.BaselineDir + ". Huginn will fall back to config / most recent dump.");
				}
				string text3 = DumpManager.DefaultDumpRoot();
				Say("Dump started -> " + text3);
				DumpManager.Start(text3, options);
			}
			catch (Exception arg)
			{
				_logger.LogError((object)$"[Eye/Commands] dump_eye failed: {arg}");
			}
		}

		private static void Status(string[] args)
		{
			if (DumpManager.IsRunning)
			{
				Say($"Running: {DumpManager.CurrentPhase} ({DumpManager.ProgressPercentage:F0}%), overall {DumpManager.OverallProgress:F1}%");
			}
			else
			{
				Say((DumpManager.LastDumpRoot != null) ? ("Idle. Last dump: " + DumpManager.LastDumpRoot) : "Idle. No dump this session.");
			}
		}
	}
	internal static class WubarrkConfig
	{
		public enum RamProfile
		{
			Rig_16GB,
			Rig_32GB,
			Rig_64GB_Plus
		}

		public static ConfigEntry<bool> EnableMod;

		public static ConfigEntry<string> PhysicsAuthorityMode;

		public static ConfigEntry<int> DumpMaxFileSizeMB;

		public static ConfigEntry<bool> DeepDiagnostics;

		public static ConfigEntry<int> BurstObjectsPerFrame;

		public static ConfigEntry<RamProfile> SystemMemoryProfile;

		public static ConfigEntry<int> DifferThreadCount;

		public static ConfigEntry<string> ApiAssemblyFilter;

		public static ConfigEntry<bool> ZdoIncludeData;

		public static ConfigEntry<bool> ForceGlobalActiveArea;

		public static ConfigEntry<bool> DumpLocalization;

		public static ConfigEntry<string> HuginnBaselineDir;

		public static ConfigEntry<int> HuginnMaxDeltasPerRecord;

		public static ConfigEntry<bool> AutoDumpOnWorldLoad;

		public static ConfigEntry<float> AutoDumpDelaySeconds;

		public static ConfigEntry<bool> AutoDumpQuit;

		public static ConfigEntry<bool> ApiIlFingerprints;

		public static ConfigEntry<string> ScanPluginDirs;

		public static ConfigEntry<bool> HuginnMarkdownReport;

		public static void Bind(ConfigFile Config)
		{
			EnableMod = Config.Bind<bool>("Core", "EnableMod", true, "Turns the mod on or off. Leave this on unless you're troubleshooting.");
			PhysicsAuthorityMode = Config.Bind<string>("Core", "PhysicsAuthorityMode", "server", "Who controls physics: the server or the client. If you don't know, leave it alone.");
			DumpMaxFileSizeMB = Config.Bind<int>("Storage", "DumpMaxFileSizeMB", 1024, "Maximum file size for a single JSON dump file in MB before it splits. Default 1024 (1GB).");
			if (DumpMaxFileSizeMB.Value <= 0 || DumpMaxFileSizeMB.Value > 10240)
			{
				DumpMaxFileSizeMB.Value = 1024;
			}
			DeepDiagnostics = Config.Bind<bool>("Diagnostics", "DeepDiagnostics", false, "Extra logging and extra detail. Helps debugging. Slows things down.");
			BurstObjectsPerFrame = Config.Bind<int>("Performance", "BurstObjectsPerFrame", 50, "How many objects the Async Deep Scanner processes per frame. Lower this if the game stutters during a dump.");
			SystemMemoryProfile = Config.Bind<RamProfile>("Hardware", "SystemMemoryProfile", RamProfile.Rig_16GB, "Select your system RAM. Higher profiles drastically speed up processing but will consume more RAM. Default is 16GB (Safe Mode).");
			DifferThreadCount = Config.Bind<int>("Hardware", "DifferThreadCount", 4, "Number of CPU threads Huginn's Report uses for diffing. Clamped between 1 and 16.");
			if (DifferThreadCount.Value < 1)
			{
				DifferThreadCount.Value = 1;
			}
			if (DifferThreadCount.Value > 16)
			{
				DifferThreadCount.Value = 16;
			}
			ApiAssemblyFilter = Config.Bind<string>("API", "ApiAssemblyFilter", "assembly_*,gui_framework,Splatform", "Comma-separated assembly names the API and enum dumps cover. A trailing * is a prefix wildcard. Use * alone to dump every loaded assembly (mscorlib, Unity, BepInEx...), which is 10x the size and mostly noise.");
			ZdoIncludeData = Config.Bind<bool>("ZDO", "ZdoIncludeData", true, "Write every key/value each ZDO carries (health, owner, inventory strings, ...) into ZDO_Dump.json, with keys named via ZDOVars. Off = identity, prefab and position only.");
			ForceGlobalActiveArea = Config.Bind<bool>("ZDO", "ForceGlobalActiveArea", false, "Patch ZNetScene so every ZDO in the world counts as inside the active area for the WHOLE session. The ZDO dump reads ZDOMan directly and does not need this on a host; it makes the game instantiate every object in the world and costs a lot of memory and frame time. Leave off unless you are hunting ghost objects.");
			DumpLocalization = Config.Bind<bool>("Registry", "DumpLocalization", true, "Include the full localization table (every token -> text in the selected language) in Registry_Dump.json. Roughly 10k records.");
			HuginnBaselineDir = Config.Bind<string>("Huginn", "HuginnBaselineDir", "", "Full path of the dump directory Huginn's Report compares against. Empty = the most recent earlier dump under WubarrksEye_Dumps. Override per run with: dump_eye baseline=<dir>");
			HuginnMaxDeltasPerRecord = Config.Bind<int>("Huginn", "HuginnMaxDeltasPerRecord", 200, "Maximum field-level deltas listed for one CHANGED record before the list is truncated.");
			if (HuginnMaxDeltasPerRecord.Value < 1)
			{
				HuginnMaxDeltasPerRecord.Value = 1;
			}
			AutoDumpOnWorldLoad = Config.Bind<bool>("Automation", "AutoDumpOnWorldLoad", false, "Run the full dump automatically once the world is populated. Meant for dedicated servers, which have no console to type dump_eye into. Fires once per process.");
			AutoDumpDelaySeconds = Config.Bind<float>("Automation", "AutoDumpDelaySeconds", 20f, "Seconds to wait after the world is populated before the automatic dump starts, so late mod registrations settle.");
			AutoDumpQuit = Config.Bind<bool>("Automation", "AutoDumpQuit", false, "Quit the application when the automatic dump finishes. Combine with AutoDumpOnWorldLoad for a one-shot headless baseline.");
			ApiIlFingerprints = Config.Bind<bool>("API", "ApiIlFingerprints", true, "Add a MethodBodies table to every API_Dump.json type: a hash of each method's normalized IL. Lets Huginn report BodyChanged for methods whose signature did not move, which is most of what a game update is. Costs about 10 s.");
			ScanPluginDirs = Config.Bind<string>("ModImpact", "ScanPluginDirs", "", "Extra folders of plugin DLLs for ModImpact_Dump.json to scan statically (semicolon separated), in addition to every plugin BepInEx loaded. Use it from a clean profile to check a whole mod-manager profile against a new game build without loading the mods. Override per run with: dump_eye scan=<dir>");
			HuginnMarkdownReport = Config.Bind<bool>("Huginn", "HuginnMarkdownReport", true, "Also write Huginn_Report.md: a human-readable summary (breaking API changes, ripples, renames, new content, mod impact) next to the JSON report.");
		}
	}
	internal static class WubarrkLogger
	{
		internal static void Initialize(ManualLogSource log)
		{
		}

		private static string Colorize(string message)
		{
			try
			{
				if (message.Contains("[Eye]"))
				{
					return "<color=#00FFFF>" + message + "</color>";
				}
				if (message.Contains("[Error]"))
				{
					return "<color=#FF0000>" + message + "</color>";
				}
				return message;
			}
			catch
			{
				return message;
			}
		}

		internal static void Info(string message)
		{
			try
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)Colorize("[WubarrksEye] " + message));
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"[Eye] Logger Failed: {arg}");
				}
			}
		}

		internal static void Warn(string message)
		{
			try
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)Colorize("[WubarrksEye] " + message));
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"[Eye] Logger Failed: {arg}");
				}
			}
		}

		internal static void Error(string message)
		{
			try
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)Colorize("[WubarrksEye] " + message));
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"[Eye] Logger Failed: {arg}");
				}
			}
		}

		internal static void MaskedError(string message)
		{
			try
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)Colorize("[WubarrksEye] " + message));
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"[Eye] Logger Failed: {arg}");
				}
			}
		}
	}
}
namespace WubarrksEye.Core.UI
{
	public class EyeUIManager : MonoBehaviour
	{
		private bool _showConfigWindow;

		private bool _showHud = true;

		public static bool DumpAgentMLOptions = false;

		public static bool DumpApiOptions = true;

		public static bool DumpPrefabsOptions = true;

		public static bool DumpSceneOptions = true;

		public static bool DumpZDOOptions = true;

		public static bool DumpObjectDBOptions = true;

		public static bool DumpValuesOptions = true;

		public static bool DumpRegistryOptions = true;

		public static bool DumpCallGraphOptions = true;

		public static bool DumpModImpactOptions = true;

		public static bool HuginnsReportEnabled = true;

		public static bool HuginnsReportMLFormat = true;

		private Rect _windowRect = new Rect(20f, 20f, 470f, 470f);

		private Rect _hudRect = new Rect(20f, 20f, 320f, 110f);

		private GUIStyle _windowStyle;

		private GUIStyle _labelStyle;

		private GUIStyle _headerStyle;

		private GUIStyle _buttonStyle;

		private bool _stylesInitialized;

		public static EyeUIManager Instance { get; private set; }

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			Instance = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				WubarrkLogger.Info("[Eye.UI] Headless (no graphics device): HUD and F8 window disabled. Use dump_eye or [Automation] AutoDumpOnWorldLoad.");
				((Behaviour)this).enabled = false;
			}
			else
			{
				WubarrkLogger.Info("[Eye.UI] UIManager initialized. Press F8 to toggle Config window, F9 to toggle HUD.");
			}
		}

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)289))
			{
				_showConfigWindow = !_showConfigWindow;
			}
			if (Input.GetKeyDown((KeyCode)290))
			{
				_showHud = !_showHud;
			}
		}

		private void InitializeStyles()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Expected O, but got Unknown
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			if (!_stylesInitialized)
			{
				Texture2D val = new Texture2D(1, 1);
				val.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.85f));
				val.Apply();
				Texture2D val2 = new Texture2D(1, 1);
				val2.SetPixel(0, 0, new Color(0.2f, 0.2f, 0.2f, 0.9f));
				val2.Apply();
				_windowStyle = new GUIStyle(GUI.skin.window);
				_windowStyle.normal.background = val;
				_windowStyle.normal.textColor = new Color(1f, 0.84f, 0f);
				_windowStyle.focused.textColor = new Color(1f, 0.84f, 0f);
				_windowStyle.onNormal.textColor = new Color(1f, 0.84f, 0f);
				_labelStyle = new GUIStyle(GUI.skin.label);
				_labelStyle.normal.textColor = new Color(1f, 0.84f, 0f);
				_headerStyle = new GUIStyle(GUI.skin.label);
				_headerStyle.normal.textColor = new Color(1f, 0.84f, 0f);
				_headerStyle.fontStyle = (FontStyle)1;
				_headerStyle.fontSize = 14;
				_buttonStyle = new GUIStyle(GUI.skin.button);
				_buttonStyle.normal.background = val2;
				_buttonStyle.normal.textColor = new Color(1f, 0.84f, 0f);
				_stylesInitialized = true;
			}
		}

		private void OnGUI()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			InitializeStyles();
			if (_showHud && !_showConfigWindow)
			{
				DrawHUD();
			}
			if (_showConfigWindow)
			{
				_windowRect = GUI.Window(9999, _windowRect, new WindowFunction(DrawConfigWindow), "TheEye 2.3.2 - Developer Console", _windowStyle);
			}
		}

		private void DrawHUD()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			GUI.Box(_hudRect, "", _windowStyle);
			GUILayout.BeginArea(_hudRect);
			GUILayout.Label("TheEye HUD 2.3.2", _headerStyle, Array.Empty<GUILayoutOption>());
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				int num = ((ZDOMan.instance != null) ? ZDOMan.instance.m_objectsByID.Count : 0);
				GUILayout.Label($"Active ZDOs: {num}", _labelStyle, Array.Empty<GUILayoutOption>());
			}
			else
			{
				GUILayout.Label("Waiting for game...", _labelStyle, Array.Empty<GUILayoutOption>());
			}
			if (DumpManager.IsRunning)
			{
				GUILayout.Label($"Total Progress: {DumpManager.OverallProgress:F1}%", _labelStyle, Array.Empty<GUILayoutOption>());
				GUILayout.Label($"Phase: {DumpManager.CurrentPhase} ({DumpManager.ProgressPercentage:F0}%)", _labelStyle, Array.Empty<GUILayoutOption>());
			}
			else
			{
				GUILayout.Label("Status: Idle", _labelStyle, Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndArea();
		}

		private void DrawConfigWindow(int windowID)
		{
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.Label("Deep Dump Controls", _headerStyle, Array.Empty<GUILayoutOption>());
			if (DumpManager.IsRunning)
			{
				GUILayout.Label($"Total Progress: {DumpManager.OverallProgress:F1}%", _labelStyle, Array.Empty<GUILayoutOption>());
				GUILayout.Label($"Phase: {DumpManager.CurrentPhase} ({DumpManager.ProgressPercentage:F0}%)", _labelStyle, Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("Cancel Dump", _buttonStyle, Array.Empty<GUILayoutOption>()))
				{
					DumpManager.Cancel();
				}
			}
			else
			{
				DumpAgentMLOptions = GUILayout.Toggle(DumpAgentMLOptions, "Also build the AI Agent ML bundle (.zip of .jsonl)", Array.Empty<GUILayoutOption>());
				DumpApiOptions = GUILayout.Toggle(DumpApiOptions, "Dump API / Types (game assemblies, full member surface)", Array.Empty<GUILayoutOption>());
				DumpPrefabsOptions = GUILayout.Toggle(DumpPrefabsOptions, "Dump Prefabs (component lists)", Array.Empty<GUILayoutOption>());
				DumpSceneOptions = GUILayout.Toggle(DumpSceneOptions, "Dump Active Scene Objects", Array.Empty<GUILayoutOption>());
				DumpZDOOptions = GUILayout.Toggle(DumpZDOOptions, "Dump ZDO State (with key/values)", Array.Empty<GUILayoutOption>());
				DumpObjectDBOptions = GUILayout.Toggle(DumpObjectDBOptions, "Dump ObjectDB (Items & Recipes)", Array.Empty<GUILayoutOption>());
				DumpValuesOptions = GUILayout.Toggle(DumpValuesOptions, "Dump Values (field contents)", Array.Empty<GUILayoutOption>());
				DumpRegistryOptions = GUILayout.Toggle(DumpRegistryOptions, "Dump Registries (enums, spawns, env, events, pieces, commands, localization)", Array.Empty<GUILayoutOption>());
				DumpCallGraphOptions = GUILayout.Toggle(DumpCallGraphOptions, "Dump Call Graph (IL call / field edges / RPC names)", Array.Empty<GUILayoutOption>());
				DumpModImpactOptions = GUILayout.Toggle(DumpModImpactOptions, "Dump Mod Impact (every plugin's game references resolved against this build)", Array.Empty<GUILayoutOption>());
				GUILayout.Space(10f);
				GUILayout.Label("Huginn's Report (structural diff against a baseline)", _headerStyle, Array.Empty<GUILayoutOption>());
				HuginnsReportEnabled = GUILayout.Toggle(HuginnsReportEnabled, "Run Huginn's Report after the dump", Array.Empty<GUILayoutOption>());
				if (HuginnsReportEnabled)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					if (GUILayout.Toggle(!HuginnsReportMLFormat, "Human Readable (.json)", Array.Empty<GUILayoutOption>()))
					{
						HuginnsReportMLFormat = false;
					}
					if (GUILayout.Toggle(HuginnsReportMLFormat, "AI Agent Format (.jsonl)", Array.Empty<GUILayoutOption>()))
					{
						HuginnsReportMLFormat = true;
					}
					GUILayout.EndHorizontal();
					string text = ((WubarrkConfig.HuginnBaselineDir != null) ? WubarrkConfig.HuginnBaselineDir.Value : "");
					GUILayout.Label(string.IsNullOrEmpty(text) ? "<color=#888888>Baseline: most recent earlier dump (set [Huginn] HuginnBaselineDir or use dump_eye baseline=<dir>)</color>" : ("<color=#888888>Baseline: " + text + "</color>"), _labelStyle, Array.Empty<GUILayoutOption>());
				}
				GUILayout.Space(10f);
				if (GUILayout.Button("Start Dump", _buttonStyle, Array.Empty<GUILayoutOption>()))
				{
					DumpManager.DumpOptions options = new DumpManager.DumpOptions
					{
						DumpAgentML = DumpAgentMLOptions,
						DumpAPI = DumpApiOptions,
						DumpPrefabs = DumpPrefabsOptions,
						DumpScene = DumpSceneOptions,
						DumpZDOs = DumpZDOOptions,
						DumpObjectDB = DumpObjectDBOptions,
						DumpValues = DumpValuesOptions,
						DumpRegistry = DumpRegistryOptions,
						DumpCallGraph = DumpCallGraphOptions,
						DumpModImpact = DumpModImpactOptions,
						ScanPluginDirs = null,
						RunHuginnsReport = HuginnsReportEnabled,
						HuginnsReportMLFormat = HuginnsReportMLFormat,
						BaselineDir = null
					};
					DumpManager.Start(DumpManager.DefaultDumpRoot(), options);
				}
				if (DumpManager.LastDumpRoot != null)
				{
					GUILayout.Label("<color=#888888>Last: " + DumpManager.LastDumpRoot + "</color>", _labelStyle, Array.Empty<GUILayoutOption>());
				}
			}
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
		}
	}
}
namespace WubarrksEye.Core.Patches
{
	public static class ZDOExistencePatch
	{
		public static bool PrefixOutsideActiveArea(ref bool __result)
		{
			__result = false;
			return false;
		}

		public static bool PrefixInActiveArea(ref bool __result)
		{
			__result = true;
			return false;
		}
	}
}
namespace WubarrksEye.Core.Dumpers
{
	public class ApiExtractor : IDataExtractor
	{
		private const BindingFlags Declared = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		public string ExtractorName => "API Reflection";

		public string OutputFileName => "API_Dump.json";

		public IEnumerator ExtractData(StreamWriter writer, int maxBytes)
		{
			return Extract(writer, minifiedJsonl: false);
		}

		public IEnumerator ExtractDataToZip(StreamWriter writer)
		{
			return Extract(writer, minifiedJsonl: true);
		}

		internal static bool IsGameAssembly(Assembly asm)
		{
			string name;
			try
			{
				name = asm.GetName().Name;
			}
			catch
			{
				return false;
			}
			return IsGameAssemblyName(name);
		}

		internal static bool IsGameAssemblyName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			string text = ((WubarrkConfig.ApiAssemblyFilter != null) ? WubarrkConfig.ApiAssemblyFilter.Value : "");
			if (string.IsNullOrWhiteSpace(text))
			{
				text = "assembly_*,gui_framework,Splatform";
			}
			string[] array = text.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0)
				{
					continue;
				}
				if (text2 == "*")
				{
					return true;
				}
				if (text2.EndsWith("*"))
				{
					if (name.StartsWith(text2.Substring(0, text2.Length - 1), StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
				}
				else if (string.Equals(name, text2, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool IsCompilerGenerated(Type t)
		{
			string text = t.FullName ?? t.Name;
			if (text.IndexOf('<') < 0 && text.IndexOf("c__DisplayClass", StringComparison.Ordinal) < 0 && text.IndexOf("d__", StringComparison.Ordinal) < 0)
			{
				return text.IndexOf("PrivateImplementationDetails", StringComparison.Ordinal) >= 0;
			}
			return true;
		}

		internal static List<Type> GameTypes()
		{
			List<Type> list = new List<Type>();
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				if (!IsGameAssembly(assembly))
				{
					continue;
				}
				Type[] array;
				try
				{
					array = assembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					array = ex.Types.Where((Type t) => t != null).ToArray();
				}
				catch
				{
					continue;
				}
				Type[] array2 = array;
				foreach (Type type in array2)
				{
					if (!(type == null) && !IsCompilerGenerated(type))
					{
						list.Add(type);
					}
				}
			}
			list.Sort((Type a, Type b) => string.CompareOrdinal(a.FullName, b.FullName));
			return list;
		}

		private IEnumerator Extract(StreamWriter writer, bool minifiedJsonl)
		{
			List<Type> types = GameTypes();
			int total = types.Count;
			int batchSize = 50;
			if (WubarrkConfig.SystemMemoryProfile.Value == WubarrkConfig.RamProfile.Rig_32GB)
			{
				batchSize = 200;
			}
			if (WubarrkConfig.SystemMemoryProfile.Value == WubarrkConfig.RamProfile.Rig_64GB_Plus)
			{
				batchSize = 1000;
			}
			bool isFirst = true;
			for (int i = 0; i < total; i++)
			{
				if (DumpManager._cancelRequested)
				{
					break;
				}
				Type type = types[i];
				JObject val;
				try
				{
					val = DumpType(type);
				}
				catch (Exception ex)
				{
					val = new JObject();
					val["Type"] = JToken.op_Implicit("API_Type");
					val["FullName"] = JToken.op_Implicit(type.FullName);
					val["<error>"] = JToken.op_Implicit(ex.GetType().Name);
				}
				if (minifiedJsonl)
				{
					writer.WriteLine(((JToken)val).ToString((Formatting)0, Array.Empty<JsonConverter>()));
				}
				else
				{
					if (!isFirst)
					{
						writer.Write(",\n");
					}
					writer.Write(((JToken)val).ToString((Formatting)1, Array.Empty<JsonConverter>()));
					isFirst = false;
				}
				if (i % batchSize == 0)
				{
					writer.Flush();
					DumpManager._progress = (float)i / (float)Math.Max(1, total) * 100f;
					yield return null;
				}
			}
			writer.Flush();
			DumpManager._progress = 100f;
			WubarrkLogger.Info($"[Eye.API] {total} types written.");
		}

		internal static string TypeName(Type t)
		{
			if (t == null)
			{
				return null;
			}
			if (t.IsByRef)
			{
				return TypeName(t.GetElementType()) + "&";
			}
			if (t.IsPointer)
			{
				return TypeName(t.GetElementType()) + "*";
			}
			if (t.IsArray)
			{
				return TypeName(t.GetElementType()) + "[" + new string(',', t.GetArrayRank() - 1) + "]";
			}
			if (t.IsGenericParameter)
			{
				return t.Name;
			}
			if (t.IsGenericType)
			{
				Type genericTypeDefinition = t.GetGenericTypeDefinition();
				string text = genericTypeDefinition.FullName ?? genericTypeDefinition.Name;
				int num = text.IndexOf('`');
				if (num >= 0)
				{
					text = text.Substring(0, num);
				}
				return text + "<" + string.Join(",", t.GetGenericArguments().Select(TypeName)) + ">";
			}
			return t.FullName ?? t.Name;
		}

		private static string Visibility(MethodBase m)
		{
			return ApiDumpWriter.GetVisibility(m);
		}

		private static string FormatSignature(MethodInfo m)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(ApiDumpWriter.GetMethodModifiers(m)).Append(' ');
			stringBuilder.Append(TypeName(m.ReturnType)).Append(' ').Append(m.Name);
			if (m.IsGenericMethod)
			{
				stringBuilder.Append('<').Append(string.Join(", ", from x in m.GetGenericArguments()
					select x.Name)).Append('>');
			}
			stringBuilder.Append('(');
			ParameterInfo[] parameters = m.GetParameters();
			for (int num = 0; num < parameters.Length; num++)
			{
				if (num > 0)
				{
					stringBuilder.Append(", ");
				}
				if (parameters[num].IsOut)
				{
					stringBuilder.Append("out ");
				}
				else if (parameters[num].ParameterType.IsByRef)
				{
					stringBuilder.Append("ref ");
				}
				stringBuilder.Append(TypeName(parameters[num].ParameterType.IsByRef ? parameters[num].ParameterType.GetElementType() : parameters[num].ParameterType));
				stringBuilder.Append(' ').Append(parameters[num].Name);
			}
			stringBuilder.Append(')');
			return stringBuilder.ToString();
		}

		private static string MethodKey(MethodBase m)
		{
			string text = m.Name;
			if (m.IsGenericMethod)
			{
				text = text + "<" + string.Join(",", from a in m.GetGenericArguments()
					select a.Name) + ">";
			}
			return text + "(" + string.Join(",", from p in m.GetParameters()
				select TypeName(p.ParameterType)) + ")";
		}

		private static JObject DumpType(Type t)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Expected O, but got Unknown
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_043f: Expected O, but got Unknown
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Expected O, but got Unknown
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Expected O, but got Unknown
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Expected O, but got Unknown
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Expected O, but got Unknown
			//IL_08f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ff: Expected O, but got Unknown
			//IL_08ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0906: Expected O, but got Unknown
			//IL_0948: Unknown result type (might be due to invalid IL or missing references)
			//IL_094f: Expected O, but got Unknown
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Expected O, but got Unknown
			//IL_0550: Unknown result type (might be due to invalid IL or missing references)
			//IL_0556: Expected O, but got Unknown
			//IL_060b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0612: Expected O, but got Unknown
			//IL_068f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0696: Expected O, but got Unknown
			//IL_077a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0781: Expected O, but got Unknown
			JObject val = new JObject();
			val["Type"] = JToken.op_Implicit("API_Type");
			val["FullName"] = JToken.op_Implicit(t.FullName);
			val["Namespace"] = JToken.op_Implicit(t.Namespace);
			val["Assembly"] = JToken.op_Implicit(t.Assembly.GetName().Name);
			val["Kind"] = JToken.op_Implicit(ApiDumpWriter.GetTypeKind(t));
			val["IsAbstract"] = JToken.op_Implicit(t.IsAbstract);
			val["IsSealed"] = JToken.op_Implicit(t.IsSealed);
			val["IsNested"] = JToken.op_Implicit(t.IsNested);
			val["Visibility"] = JToken.op_Implicit((!t.IsNested) ? (t.IsPublic ? "public" : "internal") : (t.IsNestedPublic ? "public" : (t.IsNestedFamily ? "protected" : (t.IsNestedAssembly ? "internal" : "private"))));
			val["IsGenericType"] = JToken.op_Implicit(t.IsGenericType);
			if (t.IsGenericType)
			{
				val["GenericArguments"] = (JToken)new JArray((object)(from a in t.GetGenericArguments()
					select a.Name));
			}
			val["BaseType"] = JToken.op_Implicit(TypeName(t.BaseType));
			val["InheritanceChain"] = (JToken)new JArray((object)ApiDumpWriter.GetInheritanceChain(t).Skip(1).Select(TypeName));
			val["Implements"] = (JToken)new JArray((object)t.GetInterfaces().Select(TypeName).OrderBy<string, string>((string s) => s, StringComparer.Ordinal));
			val["Attributes"] = (JToken)new JArray((object)ApiDumpWriter.SafeGetCustomAttributes(t).OrderBy<string, string>((string s) => s, StringComparer.Ordinal));
			if (t.IsEnum)
			{
				JObject val2 = new JObject();
				val["EnumUnderlying"] = JToken.op_Implicit(TypeName(Enum.GetUnderlyingType(t)));
				val["IsFlags"] = JToken.op_Implicit(t.GetCustomAttributes(typeof(FlagsAttribute), inherit: false).Length != 0);
				try
				{
					Type underlyingType = Enum.GetUnderlyingType(t);
					string[] names = Enum.GetNames(t);
					Array values = Enum.GetValues(t);
					for (int num = 0; num < names.Length; num++)
					{
						object obj = Convert.ChangeType(values.GetValue(num), underlyingType, CultureInfo.InvariantCulture);
						val2[names[num]] = JToken.op_Implicit(Convert.ToString(obj, CultureInfo.InvariantCulture));
					}
				}
				catch (Exception ex)
				{
					val2["<error>"] = JToken.op_Implicit(ex.GetType().Name);
				}
				val["EnumValues"] = (JToken)(object)val2;
			}
			JObject val3 = new JObject();
			foreach (FieldInfo item in t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).OrderBy<FieldInfo, string>((FieldInfo f) => f.Name, StringComparer.Ordinal))
			{
				if (item.Name.IndexOf('<') >= 0)
				{
					continue;
				}
				string text = TypeName(item.FieldType) + " " + ApiDumpWriter.GetFieldModifiers(item);
				if (item.IsLiteral && !item.IsInitOnly)
				{
					try
					{
						text = text + " = " + Convert.ToString(item.GetRawConstantValue(), CultureInfo.InvariantCulture);
					}
					catch
					{
					}
				}
				val3[item.Name] = JToken.op_Implicit(text);
			}
			val["Fields"] = (JToken)(object)val3;
			JObject val4 = new JObject();
			foreach (PropertyInfo item2 in t.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).OrderBy<PropertyInfo, string>((PropertyInfo p) => p.Name, StringComparer.Ordinal))
			{
				string text2 = item2.Name;
				ParameterInfo[] indexParameters = item2.GetIndexParameters();
				if (indexParameters.Length != 0)
				{
					text2 = text2 + "[" + string.Join(",", indexParameters.Select((ParameterInfo x) => TypeName(x.ParameterType))) + "]";
				}
				val4[text2] = JToken.op_Implicit(TypeName(item2.PropertyType) + " " + ApiDumpWriter.GetPropertyModifiers(item2) + " " + ApiDumpWriter.GetPropertyAccessorFlags(item2));
			}
			val["Properties"] = (JToken)(object)val4;
			JObject val5 = new JObject();
			foreach (EventInfo item3 in t.GetEvents(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).OrderBy<EventInfo, string>((EventInfo e) => e.Name, StringComparer.Ordinal))
			{
				MethodInfo addMethod = item3.GetAddMethod(nonPublic: true);
				val5[item3.Name] = JToken.op_Implicit(TypeName(item3.EventHandlerType) + ((addMethod != null) ? (" " + ApiDumpWriter.GetMethodModifiers(addMethod)) : ""));
			}
			val["Events"] = (JToken)(object)val5;
			JObject val6 = new JObject();
			foreach (ConstructorInfo item4 in t.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).OrderBy<ConstructorInfo, string>(MethodKey, StringComparer.Ordinal))
			{
				val6[MethodKey(item4)] = JToken.op_Implicit(ApiDumpWriter.GetMethodModifiers(item4));
			}
			val["Constructors"] = (JToken)(object)val6;
			JObject val7 = new JObject();
			foreach (MethodInfo item5 in (from m in t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
				where !m.IsSpecialName && m.Name.IndexOf('<') < 0
				select m).OrderBy<MethodInfo, string>(MethodKey, StringComparer.Ordinal))
			{
				string text3 = MethodKey(item5);
				if (val7[text3] != null)
				{
					text3 = text3 + "#" + item5.MetadataToken;
				}
				val7[text3] = JToken.op_Implicit(FormatSignature(item5));
			}
			val["Methods"] = (JToken)(object)val7;
			if (WubarrkConfig.ApiIlFingerprints == null || WubarrkConfig.ApiIlFingerprints.Value)
			{
				JObject val8 = new JObject();
				foreach (MethodBase item6 in (from m in t.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Cast<MethodBase>().Concat(t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Cast<MethodBase>())
					where m.Name.IndexOf('<') < 0
					select m).OrderBy<MethodBase, string>(MethodKey, StringComparer.Ordinal))
				{
					string text4;
					try
					{
						text4 = IlFingerprint.Compute(item6);
					}
					catch
					{
						text4 = null;
					}
					if (text4 != null)
					{
						string text5 = MethodKey(item6);
						if (val8[text5] != null)
						{
							text5 = text5 + "#" + item6.MetadataToken;
						}
						val8[text5] = JToken.op_Implicit(text4);
					}
				}
				val["MethodBodies"] = (JToken)(object)val8;
			}
			val["NestedTypes"] = (JToken)new JArray((object)(from n in t.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic)
				where !IsCompilerGenerated(n)
				select n.Name).OrderBy<string, string>((string s) => s, StringComparer.Ordinal));
			JObject val9 = new JObject();
			val9["IsMonoBehaviour"] = JToken.op_Implicit(typeof(MonoBehaviour).IsAssignableFrom(t));
			val9["IsScriptableObject"] = JToken.op_Implicit(typeof(ScriptableObject).IsAssignableFrom(t));
			JArray val10 = new JArray();
			try
			{
				foreach (RequireComponent item7 in t.GetCustomAttributes(inherit: true).OfType<RequireComponent>())
				{
					if (item7.m_Type0 != null)
					{
						val10.Add(JToken.op_Implicit(TypeName(item7.m_Type0)));
					}
					if (item7.m_Type1 != null)
					{
						val10.Add(JToken.op_Implicit(TypeName(item7.m_Type1)));
					}
					if (item7.m_Type2 != null)
					{
						val10.Add(JToken.op_Implicit(TypeName(item7.m_Type2)));
					}
				}
			}
			catch
			{
			}
			val9["RequiredComponents"] = (JToken)(object)val10;
			val["Unity"] = (JToken)(object)val9;
			return val;
		}
	}
	public class CallGraphExtractor : IDataExtractor
	{
		private static OpCode[] _singleByteOpCodes;

		private static OpCode[] _twoByteOpCodes;

		public string ExtractorName => "Call Graph";

		public string OutputFileName => "CallGraph_Dump.json";

		public IEnumerator ExtractData(StreamWriter writer, int maxBytes)
		{
			return Extract(writer, minifiedJsonl: false, maxBytes);
		}

		public IEnumerator ExtractDataToZip(StreamWriter writer)
		{
			return Extract(writer, minifiedJsonl: true, int.MaxValue);
		}

		private IEnumerator Extract(StreamWriter writer, bool minifiedJsonl, int maxBytes)
		{
			Assembly assembly = typeof(ZNetScene).Assembly;
			Type[] types;
			try
			{
				types = assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				types = ex.Types.Where((Type t) => t != null).ToArray();
			}
			catch (Exception ex2)
			{
				WubarrkLogger.Error("[Eye.CallGraph] Could not enumerate types in " + assembly.GetName().Name + ": " + ex2.Message);
				yield break;
			}
			Array.Sort(types, (Type a, Type b) => string.CompareOrdinal(a.FullName, b.FullName));
			Dictionary<string, List<string>> calledByMap = new Dictionary<string, List<string>>();
			List<JObject> rpcRegistrations = new List<JObject>();
			int methodCount = 0;
			int typeIndex = 0;
			int batchSize = ((WubarrkConfig.SystemMemoryProfile.Value == WubarrkConfig.RamProfile.Rig_32GB) ? 200 : ((WubarrkConfig.SystemMemoryProfile.Value == WubarrkConfig.RamProfile.Rig_64GB_Plus) ? 1000 : 50));
			bool isFirst = true;
			long written = 0L;
			bool truncated = false;
			Type[] array = types;
			foreach (Type type in array)
			{
				if (DumpManager._cancelRequested || truncated)
				{
					break;
				}
				List<MethodBase> list;
				try
				{
					list = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Cast<MethodBase>().Concat(type.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
						.ToList();
				}
				catch
				{
					typeIndex++;
					continue;
				}
				foreach (MethodBase item in list)
				{
					if (DumpManager._cancelRequested)
					{
						break;
					}
					if (written >= maxBytes)
					{
						truncated = true;
						break;
					}
					JObject val = null;
					try
					{
						val = WalkMethod(item, calledByMap, rpcRegistrations);
					}
					catch (Exception ex3)
					{
						WubarrkLogger.Warn("[Eye.CallGraph] Skipped " + type.Name + "." + item.Name + ": " + ex3.GetType().Name);
					}
					if (val != null)
					{
						writeObj(val);
						methodCount++;
						if (methodCount % batchSize == 0)
						{
							writer.Flush();
							DumpManager._progress = (float)typeIndex / (float)Math.Max(1, types.Length) * 100f;
							yield return null;
						}
					}
				}
				typeIndex++;
			}
			if (truncated)
			{
				WubarrkLogger.Warn($"[Eye.CallGraph] Hit the {maxBytes / 1048576} MB cap after {methodCount} methods; forward edges truncated.");
			}
			foreach (KeyValuePair<string, List<string>> item2 in calledByMap.OrderBy<KeyValuePair<string, List<string>>, string>((KeyValuePair<string, List<string>> k) => k.Key, StringComparer.Ordinal))
			{
				if (DumpManager._cancelRequested)
				{
					break;
				}
				JObject val2 = new JObject
				{
					["Type"] = JToken.op_Implicit("Index"),
					["Kind"] = JToken.op_Implicit("CalledBy"),
					["Method"] = JToken.op_Implicit(item2.Key)
				};
				object[] array2 = item2.Value.Distinct().OrderBy<string, string>((string c) => c, StringComparer.Ordinal).ToArray();
				val2["Callers"] = (JToken)new JArray(array2);
				writeObj(val2);
				methodCount++;
				if (methodCount % batchSize == 0)
				{
					writer.Flush();
					yield return null;
				}
			}
			foreach (JObject item3 in rpcRegistrations.OrderBy<JObject, string>((JObject r) => (string)r["RpcName"], StringComparer.Ordinal).ThenBy<JObject, string>((JObject r) => (string)r["Registrar"], StringComparer.Ordinal))
			{
				if (!DumpManager._cancelRequested)
				{
					writeObj(item3);
					methodCount++;
					continue;
				}
				break;
			}
			writer.Flush();
			DumpManager._progress = 100f;
			WubarrkLogger.Info($"[Eye.CallGraph] {methodCount} records written across {types.Length} types, {rpcRegistrations.Count} RPC registrations.");
			void writeObj(JObject val3)
			{
				string text = ((JToken)val3).ToString((Formatting)(!minifiedJsonl), Array.Empty<JsonConverter>());
				if (minifiedJsonl)
				{
					writer.WriteLine(text);
				}
				else
				{
					if (!isFirst)
					{
						writer.Write(",\n");
					}
					writer.Write(text);
					isFirst = false;
				}
				written += text.Length + 2;
			}
		}

		private JObject WalkMethod(MethodBase method, Dictionary<string, List<string>> calledByMap, List<JObject> rpcRegistrations)
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Expected O, but got Unknown
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Expected O, but got Unknown
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Expected O, but got Unknown
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			MethodBody methodBody = null;
			try
			{
				methodBody = method.GetMethodBody();
			}
			catch
			{
			}
			if (methodBody == null)
			{
				return null;
			}
			byte[] iLAsByteArray = methodBody.GetILAsByteArray();
			if (iLAsByteArray == null || iLAsByteArray.Length == 0)
			{
				return null;
			}
			Module module = method.Module;
			Type[] genericTypeArguments = ((method.DeclaringType != null && method.DeclaringType.IsGenericType) ? method.DeclaringType.GetGenericArguments() : null);
			Type[] genericMethodArguments = (method.IsGenericMethod ? method.GetGenericArguments() : null);
			string text = FormatSignature(method);
			string text2 = method.DeclaringType?.Name + "." + method.Name + "(" + string.Join(",", from p in method.GetParameters()
				select p.ParameterType.FullName ?? p.ParameterType.Name) + ")";
			JObject val = new JObject();
			val["Type"] = JToken.op_Implicit(method.DeclaringType?.Name ?? "Unknown");
			val["Method"] = JToken.op_Implicit(method.Name);
			val["Signature"] = JToken.op_Implicit(text);
			MethodInfo methodInfo = method as MethodInfo;
			bool flag = methodInfo != null && methodInfo.IsVirtual && methodInfo.GetBaseDefinition() != methodInfo;
			val["ChainsToBase"] = (JToken)(flag ? ((object)JToken.op_Implicit(false)) : ((object)JValue.CreateNull()));
			JArray val2 = new JArray();
			JArray val3 = new JArray();
			JArray val4 = new JArray();
			int num = 0;
			string text3 = null;
			int num2 = 0;
			while (num2 < iLAsByteArray.Length)
			{
				OpCode opCode;
				if (iLAsByteArray[num2] == 254)
				{
					if (num2 + 1 >= iLAsByteArray.Length)
					{
						break;
					}
					opCode = _twoByteOpCodes[iLAsByteArray[num2 + 1]];
					num2 += 2;
				}
				else
				{
					opCode = _singleByteOpCodes[iLAsByteArray[num2]];
					num2++;
				}
				if (opCode.OperandType == OperandType.InlineMethod)
				{
					if (num2 + 4 > iLAsByteArray.Length)
					{
						break;
					}
					int metadataToken = BitConverter.ToInt32(iLAsByteArray, num2);
					num2 += 4;
					try
					{
						MethodBase methodBase = module.ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments);
						if (methodBase != null)
						{
							string text4 = methodBase.DeclaringType?.Name + "." + methodBase.Name + "(" + string.Join(",", from p in methodBase.GetParameters()
								select p.ParameterType.FullName ?? p.ParameterType.Name) + ")";
							JObject val5 = new JObject();
							val5["Target"] = JToken.op_Implicit(text4);
							val5["Op"] = JToken.op_Implicit(opCode.Name);
							val2.Add((JToken)(object)val5);
							if (text3 != null && methodBase.Name == "Register" && methodBase.DeclaringType != null && (methodBase.DeclaringType == typeof(ZNetView) || methodBase.DeclaringType == typeof(ZRoutedRpc) || methodBase.DeclaringType == typeof(ZRpc)))
							{
								JObject val6 = new JObject();
								val6["Type"] = JToken.op_Implicit("Index");
								val6["Kind"] = JToken.op_Implicit("RpcRegistration");
								val6["RpcName"] = JToken.op_Implicit(text3);
								val6["Via"] = JToken.op_Implicit(methodBase.DeclaringType.Name);
								val6["Registrar"] = JToken.op_Implicit(text2);
								rpcRegistrations.Add(val6);
								text3 = null;
							}
							if (!calledByMap.TryGetValue(text4, out var value))
							{
								value = (calledByMap[text4] = new List<string>());
							}
							value.Add(text2);
							if (flag && opCode == OpCodes.Call && methodBase is MethodInfo methodInfo2 && methodInfo2.Name == methodInfo.Name && methodInfo2.DeclaringType != null && methodInfo.DeclaringType != null && methodInfo2.DeclaringType != methodInfo.DeclaringType && methodInfo2.DeclaringType.IsAssignableFrom(methodInfo.DeclaringType))
							{
								val["ChainsToBase"] = JToken.op_Implicit(true);
							}
						}
					}
					catch
					{
						num++;
					}
					continue;
				}
				if (opCode.OperandType == OperandType.InlineField)
				{
					if (num2 + 4 > iLAsByteArray.Length)
					{
						break;
					}
					int metadataToken2 = BitConverter.ToInt32(iLAsByteArray, num2);
					num2 += 4;
					try
					{
						FieldInfo fieldInfo = module.ResolveField(metadataToken2, genericTypeArguments, genericMethodArguments);
						if (fieldInfo != null)
						{
							string text5 = fieldInfo.DeclaringType?.Name + "." + fieldInfo.Name;
							if (opCode == OpCodes.Ldfld || opCode == OpCodes.Ldsfld || opCode == OpCodes.Ldflda || opCode == OpCodes.Ldsflda)
							{
								val3.Add(JToken.op_Implicit(text5));
							}
							else if (opCode == OpCodes.Stfld || opCode == OpCodes.Stsfld)
							{
								val4.Add(JToken.op_Implicit(text5));
							}
						}
					}
					catch
					{
						num++;
					}
					continue;
				}
				if (opCode.OperandType == OperandType.InlineSwitch)
				{
					if (num2 + 4 > iLAsByteArray.Length)
					{
						break;
					}
					int num3 = BitConverter.ToInt32(iLAsByteArray, num2);
					num2 += 4;
					num2 += num3 * 4;
					continue;
				}
				switch (opCode.OperandType)
				{
				case OperandType.InlineString:
					if (num2 + 4 > iLAsByteArray.Length)
					{
						num2 = iLAsByteArray.Length;
						break;
					}
					try
					{
						text3 = module.ResolveString(BitConverter.ToInt32(iLAsByteArray, num2));
					}
					catch
					{
					}
					num2 += 4;
					break;
				case OperandType.InlineBrTarget:
				case OperandType.InlineI:
				case OperandType.InlineSig:
				case OperandType.InlineTok:
				case OperandType.InlineType:
				case OperandType.ShortInlineR:
					num2 += 4;
					break;
				case OperandType.InlineI8:
				case OperandType.InlineR:
					num2 += 8;
					break;
				case OperandType.InlineVar:
					num2 += 2;
					break;
				case OperandType.ShortInlineBrTarget:
				case OperandType.ShortInlineI:
				case OperandType.ShortInlineVar:
					num2++;
					break;
				}
			}
			val["Calls"] = (JToken)(object)val2;
			val["Reads"] = (JToken)(object)val3;
			val["Writes"] = (JToken)(object)val4;
			val["Unresolved"] = JToken.op_Implicit(num);
			return val;
		}

		static CallGraphExtractor()
		{
			_singleByteOpCodes = new OpCode[256];
			_twoByteOpCodes = new OpCode[256];
			FieldInfo[] fields = typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!(fieldInfo.FieldType != typeof(OpCode)))
				{
					OpCode opCode = (OpCode)fieldInfo.GetValue(null);
					ushort num = (ushort)opCode.Value;
					if (num < 256)
					{
						_singleByteOpCodes[num] = opCode;
					}
					else if ((num & 0xFF00) == 65024)
					{
						_twoByteOpCodes[num & 0xFF] = opCode;
					}
				}
			}
		}

		private string FormatSignature(MethodBase m)
		{
			string text = "";
			if (m.IsPublic)
			{
				text += "public ";
			}
			else if (m.IsFamily)
			{
				text += "protected ";
			}
			else if (m.IsAssembly)
			{
				text += "internal ";
			}
			else if (m.IsPrivate)
			{
				text += "private ";
			}
			if (m.IsStatic)
			{
				text += "static ";
			}
			else if (m.IsVirtual)
			{
				text = (((m.Attributes & MethodAttributes.VtableLayoutMask) == 0) ? (text + "override ") : (text + "virtual "));
			}
			if (m.IsAbstract)
			{
				text += "abstract ";
			}
			string text2 = "void";
			if (m is MethodInfo methodInfo)
			{
				text2 = methodInfo.ReturnType.FullName ?? methodInfo.ReturnType.Name;
			}
			IEnumerable<string> values = from x in m.GetParameters()
				select (x.ParameterType.FullName ?? x.ParameterType.Name) + " " + x.Name;
			return text + text2 + " " + m.Name + "(" + string.Join(", ", values) + ")";
		}
	}
	public interface IDataExtractor
	{
		string ExtractorName { get; }

		string OutputFileName { get; }

		IEnumerator ExtractData(StreamWriter writer, int maxBytes);

		IEnumerator ExtractDataToZip(StreamWriter writer);
	}
	internal static class IlFingerprint
	{
		internal static readonly OpCode[] SingleByte;

		internal static readonly OpCode[] TwoByte;

		static IlFingerprint()
		{
			SingleByte = new OpCode[256];
			TwoByte = new OpCode[256];
			FieldInfo[] fields = typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!(fieldInfo.FieldType != typeof(OpCode)))
				{
					OpCode opCode = (OpCode)fieldInfo.GetValue(null);
					ushort num = (ushort)opCode.Value;
					if (num < 256)
					{
						SingleByte[num] = opCode;
					}
					else if ((num & 0xFF00) == 65024)
					{
						TwoByte[num & 0xFF] = opCode;
					}
				}
			}
		}

		public static string Compute(MethodBase m)
		{
			List<string> list = Tokens(m, null);
			if (list == null)
			{
				return null;
			}
			ulong num = 14695981039346656037uL;
			foreach (string item in list)
			{
				foreach (char c in item)
				{
					num ^= c;
					num *= 1099511628211L;
				}
				num ^= 0xA;
				num *= 1099511628211L;
			}
			int num2 = 0;
			try
			{
				num2 = m.GetMethodBody().GetILAsByteArray().Length;
			}
			catch
			{
			}
			return num.ToString("x16") + ":" + num2.ToString(CultureInfo.InvariantCulture);
		}

		public static void Literals(MethodBase m, List<string> into)
		{
			Tokens(m, into);
		}

		private static List<string> Tokens(MethodBase m, List<string> literals)
		{
			MethodBody methodBody;
			try
			{
				methodBody = m.GetMethodBody();
			}
			catch
			{
				return null;
			}
			if (methodBody == null)
			{
				return null;
			}
			byte[] iLAsByteArray = methodBody.GetILAsByteArray();
			if (iLAsByteArray == null || iLAsByteArray.Length == 0)
			{
				return null;
			}
			Module module = m.Module;
			Type[] genericTypeArguments = null;
			Type[] genericMethodArguments = null;
			try
			{
				genericTypeArguments = ((m.DeclaringType != null && m.DeclaringType.IsGenericType) ? m.DeclaringType.GetGenericArguments() : null);
			}
			catch
			{
			}
			try
			{
				genericMethodArguments = (m.IsGenericMethod ? m.GetGenericArguments() : null);
			}
			catch
			{
			}
			List<string> list = ((literals == null) ? new List<string>(iLAsByteArray.Length / 2 + 8) : null);
			if (list != null)
			{
				StringBuilder stringBuilder = new StringBuilder(".locals ");
				try
				{
					foreach (LocalVariableInfo localVariable in methodBody.LocalVariables)
					{
						stringBuilder.Append(ApiExtractor.TypeName(localVariable.LocalType)).Append(',');
					}
				}
				catch
				{
					stringBuilder.Append('?');
				}
				list.Add(stringBuilder.ToString());
			}
			int num = 0;
			while (num < iLAsByteArray.Length)
			{
				OpCode opCode;
				if (iLAsByteArray[num] == 254)
				{
					if (num + 1 >= iLAsByteArray.Length)
					{
						break;
					}
					opCode = TwoByte[iLAsByteArray[num + 1]];
					num += 2;
				}
				else
				{
					opCode = SingleByte[iLAsByteArray[num]];
					num++;
				}
				if (opCode.Name == null)
				{
					break;
				}
				string text = "";
				switch (opCode.OperandType)
				{
				case OperandType.InlineMethod:
				{
					if (num + 4 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					int metadataToken4 = BitConverter.ToInt32(iLAsByteArray, num);
					num += 4;
					try
					{
						MethodBase methodBase = module.ResolveMethod(metadataToken4, genericTypeArguments, genericMethodArguments);
						text = ((methodBase == null) ? "?m" : MethodName(methodBase));
					}
					catch
					{
						text = "?m";
					}
					break;
				}
				case OperandType.InlineField:
				{
					if (num + 4 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					int metadataToken2 = BitConverter.ToInt32(iLAsByteArray, num);
					num += 4;
					try
					{
						FieldInfo fieldInfo = module.ResolveField(metadataToken2, genericTypeArguments, genericMethodArguments);
						text = ((fieldInfo == null) ? "?f" : (ApiExtractor.TypeName(fieldInfo.DeclaringType) + "::" + fieldInfo.Name));
					}
					catch
					{
						text = "?f";
					}
					break;
				}
				case OperandType.InlineType:
				{
					if (num + 4 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					int metadataToken5 = BitConverter.ToInt32(iLAsByteArray, num);
					num += 4;
					try
					{
						text = ApiExtractor.TypeName(module.ResolveType(metadataToken5, genericTypeArguments, genericMethodArguments)) ?? "?t";
					}
					catch
					{
						text = "?t";
					}
					break;
				}
				case OperandType.InlineTok:
				{
					if (num + 4 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					int metadataToken = BitConverter.ToInt32(iLAsByteArray, num);
					num += 4;
					try
					{
						MemberInfo memberInfo = module.ResolveMember(metadataToken, genericTypeArguments, genericMethodArguments);
						text = ((memberInfo is Type) ? ApiExtractor.TypeName((Type)memberInfo) : ((memberInfo is MethodBase) ? MethodName((MethodBase)memberInfo) : ((memberInfo is FieldInfo) ? (ApiExtractor.TypeName(memberInfo.DeclaringType) + "::" + memberInfo.Name) : "?k")));
					}
					catch
					{
						text = "?k";
					}
					break;
				}
				case OperandType.InlineString:
				{
					if (num + 4 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					int metadataToken3 = BitConverter.ToInt32(iLAsByteArray, num);
					num += 4;
					try
					{
						string text2 = module.ResolveString(metadataToken3);
						text = "\"" + text2 + "\"";
						if (literals != null && text2 != null)
						{
							literals.Add(text2);
						}
					}
					catch
					{
						text = "?s";
					}
					break;
				}
				case OperandType.InlineSig:
					num += 4;
					text = "sig";
					break;
				case OperandType.InlineBrTarget:
				{
					if (num + 4 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					int num2 = BitConverter.ToInt32(iLAsByteArray, num);
					num += 4;
					text = "->" + num2.ToString(CultureInfo.InvariantCulture);
					break;
				}
				case OperandType.ShortInlineBrTarget:
					if (num < iLAsByteArray.Length)
					{
						text = "->" + ((sbyte)iLAsByteArray[num]).ToString(CultureInfo.InvariantCulture);
						num++;
					}
					break;
				case OperandType.InlineSwitch:
				{
					if (num + 4 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					int num3 = BitConverter.ToInt32(iLAsByteArray, num);
					num += 4;
					StringBuilder stringBuilder2 = new StringBuilder("->[");
					for (int i = 0; i < num3; i++)
					{
						if (num + 4 > iLAsByteArray.Length)
						{
							break;
						}
						stringBuilder2.Append(BitConverter.ToInt32(iLAsByteArray, num)).Append(',');
						num += 4;
					}
					text = stringBuilder2.Append(']').ToString();
					break;
				}
				case OperandType.InlineI:
					if (num + 4 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					text = BitConverter.ToInt32(iLAsByteArray, num).ToString(CultureInfo.InvariantCulture);
					num += 4;
					break;
				case OperandType.InlineI8:
					if (num + 8 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					text = BitConverter.ToInt64(iLAsByteArray, num).ToString(CultureInfo.InvariantCulture);
					num += 8;
					break;
				case OperandType.InlineR:
					if (num + 8 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					text = BitConverter.ToDouble(iLAsByteArray, num).ToString("R", CultureInfo.InvariantCulture);
					num += 8;
					break;
				case OperandType.ShortInlineR:
					if (num + 4 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					text = BitConverter.ToSingle(iLAsByteArray, num).ToString("R", CultureInfo.InvariantCulture);
					num += 4;
					break;
				case OperandType.InlineVar:
					if (num + 2 > iLAsByteArray.Length)
					{
						num = iLAsByteArray.Length;
						break;
					}
					text = "V" + BitConverter.ToUInt16(iLAsByteArray, num).ToString(CultureInfo.InvariantCulture);
					num += 2;
					break;
				case OperandType.ShortInlineVar:
					if (num < iLAsByteArray.Length)
					{
						text = "V" + iLAsByteArray[num].ToString(CultureInfo.InvariantCulture);
						num++;
					}
					break;
				case OperandType.ShortInlineI:
					if (num < iLAsByteArray.Length)
					{
						text = ((sbyte)iLAsByteArray[num]).ToString(CultureInfo.InvariantCulture);
						num++;
					}
					break;
				default:
					num += 4;
					text = "?";
					break;
				case OperandType.InlineNone:
					break;
				}
				list?.Add((text.Length == 0) ? opCode.Name : (opCode.Name + " " + text));
			}
			if (list != null)
			{
				try
				{
					foreach (ExceptionHandlingClause exceptionHandlingClause in methodBody.ExceptionHandlingClauses)
					{
						string text3 = "";
						if (exceptionHandlingClause.Flags == ExceptionHandlingClauseOptions.Clause)
						{
							try
							{
								text3 = ApiExtractor.TypeName(exceptionHandlingClause.CatchType);
							}
							catch
							{
							}
						}
						list.Add(".eh " + exceptionHandlingClause.Flags.ToString() + " try[" + exceptionHandlingClause.TryOffset + "," + exceptionHandlingClause.TryLength + "] h[" + exceptionHandlingClause.HandlerOffset + "," + exceptionHandlingClause.HandlerLength + "] " + text3);
					}
				}
				catch
				{
				}
			}
			return list;
		}

		internal static string MethodName(MethodBase t)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(ApiExtractor.TypeName(t.DeclaringType)).Append("::").Append(t.Name);
			if (t.IsGenericMethod)
			{
				stringBuilder.Append('<');
				try
				{
					Type[] genericArguments = t.GetGenericArguments();
					foreach (Type t2 in genericArguments)
					{
						stringBuilder.Append(ApiExtractor.TypeName(t2)).Append(',');
					}
				}
				catch
				{
					stringBuilder.Append('?');
				}
				stringBuilder.Append('>');
			}
			stringBuilder.Append('(');
			try
			{
				ParameterInfo[] parameters = t.GetParameters();
				foreach (ParameterInfo parameterInfo in parameters)
				{
					stringBuilder.Append(ApiExtractor.TypeName(parameterInfo.ParameterType)).Append(',');
				}
			}
			catch
			{
				stringBuilder.Append('?');
			}
			stringBuilder.Append(')');
			return stringBuilder.ToString();
		}
	}
	public class ModImpactExtractor : IDataExtractor
	{
		private sealed class Target
		{
			public string Path;

			public string Guid;

			public string Name;

			public string Version;

			public bool Loaded;
		}

		private sealed class MemberRef
		{
			public string Kind;

			public string Ref;

			public string Assembly;

			public string Why;

			public TypeReference Type;

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

			public int MoreUsers;
		}

		private sealed class PatchSpec
		{
			public TypeReference DeclaringType;

			public string TypeName;

			public string MethodName;

			public List<TypeReference> ArgTypes;

			public int MethodType;

			public bool Unchecked;

			public string UncheckedWhy;

			public PatchSpec Clone()
			{
				return (PatchSpec)MemberwiseClone();
			}
		}

		private readonly string _scanDirs;

		private const BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly HashSet<string> ClientOnlyTypes = new HashSet<string>(StringComparer.Ordinal) { "FrameBufferScaler", "UpscaledFrameBuffer", "PrivilegeManager" };

		public string ExtractorName => "Mod Impact";

		public string OutputFileName => "ModImpact_Dump.json";

		public ModImpactExtractor(string scanDirs)
		{
			_scanDirs = scanDirs;
		}

		public IEnumerator ExtractData(StreamWriter writer, int maxBytes)
		{
			return Extract(writer, minifiedJsonl: false);
		}

		public IEnumerator ExtractDataToZip(StreamWriter writer)
		{
			return Extract(writer, minifiedJsonl: true);
		}

		private IEnumerator Extract(StreamWriter writer, bool minifiedJsonl)
		{
			bool isFirst = true;
			int written = 0;
			Action<JObject> emit = delegate(JObject val5)
			{
				if (minifiedJsonl)
				{
					writer.WriteLine(((JToken)val5).ToString((Formatting)0, Array.Empty<JsonConverter>()));
				}
				else
				{
					if (!isFirst)
					{
						writer.Write(",\n");
					}
					writer.Write(((JToken)val5).ToString((Formatting)1, Array.Empty<JsonConverter>()));
					isFirst = false;
				}
				written++;
			};
			List<Target> targets = CollectTargets();
			DefaultAssemblyResolver resolver = new DefaultAssemblyResolver();
			HashSet<string> searchDirs = new HashSet<string>(StringComparer.Ordi