Decompiled source of TheEye v1.2.9
plugins/BlackBox.WubarrksEye.dll
Decompiled 8 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BlackBox.WubarrksEye.AbyssalLedger; using BlackBox.WubarrksEye.AbyssalLedger.Aggregates; using BlackBox.WubarrksEye.AbyssalLedger.Archive; using BlackBox.WubarrksEye.AbyssalLedger.Candidates; using BlackBox.WubarrksEye.AbyssalLedger.Evidence; using BlackBox.WubarrksEye.AbyssalLedger.Promotions; using BlackBox.WubarrksEye.Adapters; using BlackBox.WubarrksEye.Codex; using BlackBox.WubarrksEye.Core; using BlackBox.WubarrksEye.Core.Commands; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("BlackBox.WubarrksEye")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BlackBox.WubarrksEye")] [assembly: AssemblyTitle("BlackBox.WubarrksEye")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } 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); } } [CompilerGenerated] private sealed class <SafeFields>d__8 : IEnumerable<FieldInfo>, IEnumerable, IEnumerator<FieldInfo>, IDisposable, IEnumerator { private int <>1__state; private FieldInfo <>2__current; private int <>l__initialThreadId; private Type t; public Type <>3__t; private FieldInfo[] <>7__wrap1; private int <>7__wrap2; FieldInfo IEnumerator<FieldInfo>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SafeFields>d__8(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_0083; } <>1__state = -1; FieldInfo[] fields; try { fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { return false; } <>7__wrap1 = fields; <>7__wrap2 = 0; goto IL_0091; IL_0091: if (<>7__wrap2 < <>7__wrap1.Length) { FieldInfo fieldInfo = <>7__wrap1[<>7__wrap2]; if (!fieldInfo.IsStatic && !fieldInfo.FieldType.IsPointer && !IsForbidden(fieldInfo.FieldType)) { <>2__current = fieldInfo; <>1__state = 1; return true; } goto IL_0083; } <>7__wrap1 = null; return false; IL_0083: <>7__wrap2++; goto IL_0091; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<FieldInfo> IEnumerable<FieldInfo>.GetEnumerator() { <SafeFields>d__8 <SafeFields>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <SafeFields>d__ = this; } else { <SafeFields>d__ = new <SafeFields>d__8(0); } <SafeFields>d__.t = <>3__t; return <SafeFields>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<FieldInfo>)this).GetEnumerator(); } } 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) { 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 != null && (val == (Object)null || !Object.op_Implicit(val))) || !_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; } [IteratorStateMachine(typeof(<SafeFields>d__8))] private static IEnumerable<FieldInfo> SafeFields(Type t) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SafeFields>d__8(-2) { <>3__t = t }; } } namespace BlackBox.WubarrksEye { [BepInPlugin("blackbox.wubarrkseye", "Wubarrk's Eye", "1.2.8")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "blackbox.wubarrkseye"; public const string PluginName = "Wubarrk's Eye"; public const string PluginVersion = "1.2.8"; private Harmony _harmony; private static ManualLogSource _log; private static AbyssalLedgerRuntime _ledgerRuntime; public static ManualLogSource Log => _log; public static AbyssalLedgerRuntime LedgerRuntime => _ledgerRuntime; private void Awake() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown _log = ((BaseUnityPlugin)this).Logger; try { BlackBoxConfig.Bind(((BaseUnityPlugin)this).Config); _log.LogInfo((object)"[Eye] BlackBoxConfig bound."); _harmony = new Harmony("blackbox.wubarrkseye"); _harmony.PatchAll(); _log.LogInfo((object)"[Eye] Harmony patches applied."); HarmonyIntelligence.Initialize(_harmony, ((BaseUnityPlugin)this).Logger); AbyssalLedgerRuntime.Initialize(); CodexBootstrapper.Initialize(); DumpRuntime.Initialize(((BaseUnityPlugin)this).Logger); InitializeAbyssalLedger(); if (_ledgerRuntime != null) { EyeDumpNotifier.Initialize(((BaseUnityPlugin)this).Logger, _ledgerRuntime); } else { _log.LogWarning((object)"[Eye] AbyssalLedgerRuntime is null; EyeDumpNotifier not initialized."); } EyeCommands.Initialize(((BaseUnityPlugin)this).Logger); BootSplash.Initialize(((BaseUnityPlugin)this).Logger); HarmonyIntelligence.HarmonyTelemetry harmony = HarmonyIntelligence.CaptureSnapshot(); LedgerSnapshot ledger = ((_ledgerRuntime != null) ? _ledgerRuntime.BuildSnapshot() : LedgerSnapshot.Empty()); CodexBootstrapper.RefreshSnapshot(); CodexSnapshot codex = CodexBootstrapper.Snapshot ?? CodexSnapshot.Empty(); DumpSnapshot dump = DumpRuntime.BuildSnapshot(); BootSplash.Render(harmony, ledger, codex, dump); _log.LogInfo((object)"[Eye] Plugin initialization complete. Wubarrk's Eye is now watching."); } catch (Exception arg) { _log.LogError((object)$"[Eye] Plugin initialization failed: {arg}"); } } 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}"); } } private static void InitializeAbyssalLedger() { try { _ledgerRuntime = AbyssalLedgerRuntime.Initialize(AbyssalLedgerConfig.CreateDefault()); _ledgerRuntime.CodexPromotionAdapter = CandidateToCodexPromotion; ManualLogSource log = _log; if (log != null) { log.LogInfo((object)"[Eye][Ledger] Abyssal Ledger runtime initialized and Codex promotion adapter wired."); } } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)("[Eye][Ledger] Failed to initialize Abyssal Ledger runtime: " + ex.Message)); } _ledgerRuntime = null; } } private static (bool succeeded, string status, string note, string error) CandidateToCodexPromotion(CandidateEntry candidate) { try { return CodexPromotionAdapter.PromoteCandidate(candidate); } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogError((object)$"[Eye][Codex] Candidate promotion failed: {ex}"); } return (false, "error", "Codex promotion threw exception", ex.Message); } } public static void NotifyDumpCreated(int dumpId, string dumpFolderPath) { try { EyeDumpNotifier.NotifyDumpCreated(dumpId, dumpFolderPath); } catch (Exception arg) { ManualLogSource log = _log; if (log != null) { log.LogError((object)$"[Eye] NotifyDumpCreated failed for dumpId={dumpId}: {arg}"); } } } public static void RequestLedgerBackup(string note = null) { if (_ledgerRuntime == null) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)"[Eye][Ledger] RequestLedgerBackup called, but runtime is null."); } return; } try { string note2 = note ?? string.Empty; _ledgerRuntime.CreateBackup(note2); ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)"[Eye][Ledger] Backup request processed."); } } catch (Exception arg) { ManualLogSource log3 = _log; if (log3 != null) { log3.LogError((object)$"[Eye][Ledger] RequestLedgerBackup failed: {arg}"); } } } } } namespace BlackBox.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; BlackBoxLogger.Info("[HarmonyBootstrap] Running PatchAllSafe for attribute-based patches..."); HarmonyPatcher.PatchAllSafe(harmony, assembly); int num = harmony.GetPatchedMethods().Count(); BlackBoxLogger.Info($"[HarmonyBootstrap] Total patched methods after bootstrap: {num}"); } catch (Exception arg) { BlackBoxLogger.Warn($"[HarmonyBootstrap] Fatal error while applying patches: {arg}"); } } } internal static class HarmonyPatcher { [CompilerGenerated] private sealed class <FindSimilarNamedMethods>d__14 : IEnumerable<MethodInfo>, IEnumerable, IEnumerator<MethodInfo>, IDisposable, IEnumerator { private int <>1__state; private MethodInfo <>2__current; private int <>l__initialThreadId; private Type type; public Type <>3__type; private string methodName; public string <>3__methodName; private string <target>5__2; private MethodInfo[] <>7__wrap2; private int <>7__wrap3; MethodInfo IEnumerator<MethodInfo>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FindSimilarNamedMethods>d__14(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <target>5__2 = null; <>7__wrap2 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_00c2; } <>1__state = -1; MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { return false; } <target>5__2 = methodName.ToLowerInvariant(); <>7__wrap2 = methods; <>7__wrap3 = 0; goto IL_00d0; IL_00d0: if (<>7__wrap3 < <>7__wrap2.Length) { MethodInfo methodInfo = <>7__wrap2[<>7__wrap3]; string text = methodInfo.Name.ToLowerInvariant(); if (!(text == <target>5__2) && (text.Contains(<target>5__2) || <target>5__2.Contains(text) || LevenshteinDistance(text, <target>5__2) <= 2)) { <>2__current = methodInfo; <>1__state = 1; return true; } goto IL_00c2; } <>7__wrap2 = null; return false; IL_00c2: <>7__wrap3++; goto IL_00d0; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodInfo> IEnumerable<MethodInfo>.GetEnumerator() { <FindSimilarNamedMethods>d__14 <FindSimilarNamedMethods>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <FindSimilarNamedMethods>d__ = this; } else { <FindSimilarNamedMethods>d__ = new <FindSimilarNamedMethods>d__14(0); } <FindSimilarNamedMethods>d__.type = <>3__type; <FindSimilarNamedMethods>d__.methodName = <>3__methodName; return <FindSimilarNamedMethods>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodInfo>)this).GetEnumerator(); } } 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 num2 = SafePatchClass(harmony, type, array3); num += num2; } 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) != 0) { 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 { BlackBoxLogger.Info("[HarmonyPatcher] " + msg); } catch { } } private static void LoggerWarning(string msg) { try { BlackBoxLogger.Warn("[HarmonyPatcher] " + msg); } catch { } } private static void LoggerDebug(string msg) { try { BlackBoxLogger.Info("[HarmonyPatcher][Debug] " + msg); } catch { } } [IteratorStateMachine(typeof(<FindSimilarNamedMethods>d__14))] private static IEnumerable<MethodInfo> FindSimilarNamedMethods(Type type, string methodName) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FindSimilarNamedMethods>d__14(-2) { <>3__type = type, <>3__methodName = methodName }; } 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 BlackBox.WubarrksEye.Core { internal static class ApiDumpWriter { [CompilerGenerated] private sealed class <GetInheritanceChain>d__2 : IEnumerable<Type>, IEnumerable, IEnumerator<Type>, IDisposable, IEnumerator { private int <>1__state; private Type <>2__current; private int <>l__initialThreadId; private Type t; public Type <>3__t; Type IEnumerator<Type>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetInheritanceChain>d__2(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; t = t.BaseType; break; } if (t != null) { <>2__current = t; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<Type> IEnumerable<Type>.GetEnumerator() { <GetInheritanceChain>d__2 <GetInheritanceChain>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetInheritanceChain>d__ = this; } else { <GetInheritanceChain>d__ = new <GetInheritanceChain>d__2(0); } <GetInheritanceChain>d__.t = <>3__t; return <GetInheritanceChain>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<Type>)this).GetEnumerator(); } } 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 i) => i.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 k = 0; k < names.Length; k++) { w.WriteLine($"{names[k]} = {(int)values.GetValue(k)}"); } } 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 m in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where !m.IsSpecialName orderby m.Name, m.GetParameters().Length select m).ToArray(); if (array3.Length == 0) { w.WriteLine("<none>"); } else { MethodInfo[] array4 = array3; foreach (MethodInfo m2 in array4) { w.WriteLine(FormatFullMethodSignature(m2)); } } 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 ==="); } private static string GetTypeKind(Type t) { if (t.IsInterface) { return "interface"; } if (t.IsEnum) { return "enum"; } if (t.IsValueType) { return "struct"; } return "class"; } [IteratorStateMachine(typeof(<GetInheritanceChain>d__2))] private static IEnumerable<Type> GetInheritanceChain(Type t) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetInheritanceChain>d__2(-2) { <>3__t = t }; } private 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>(); } } private 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); } private static string GetPropertyModifiers(PropertyInfo p) { MethodInfo methodInfo = p.GetGetMethod(nonPublic: true) ?? p.GetSetMethod(nonPublic: true); if (!(methodInfo != null)) { return ""; } return GetMethodModifiers(methodInfo); } private 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) + "}"; } private 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"; } private 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); } private 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 i = 0; i < parameters.Length; i++) { if (i > 0) { stringBuilder.Append(", "); } ParameterInfo parameterInfo = parameters[i]; 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 BlackBoxConfig { public static ConfigEntry<bool> EnableMod; public static ConfigEntry<string> PhysicsAuthorityMode; public static ConfigEntry<bool> EnableLedger; public static ConfigEntry<bool> EnableCodex; public static ConfigEntry<bool> EnablePromotions; public static ConfigEntry<int> LedgerMaxSizeMB; public static ConfigEntry<int> CodexMaxSizeMB; public static ConfigEntry<int> EyeDumpMaxFileSizeKB; public static ConfigEntry<int> EyeDumpMaxFileSizeExpertKB; public static ConfigEntry<bool> DeepDiagnostics; public static ConfigEntry<bool> LedgerDebug; public static ConfigEntry<bool> CodexDebug; public static ConfigEntry<bool> DumpAllFields; public static ConfigEntry<bool> DumpAllMethods; public static ConfigEntry<bool> DumpAllProperties; public static ConfigEntry<bool> DumpAllComponents; public static ConfigEntry<bool> EnableExpertMode; public static ConfigEntry<bool> DumpAllFieldsExpert; public static ConfigEntry<bool> DumpAllComponentsExpert; public static ConfigEntry<bool> DumpAllMethodsExpert; public static ConfigEntry<bool> DumpAllPropertiesExpert; 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."); EnableLedger = Config.Bind<bool>("Core", "EnableLedger", true, "Turns on the Ledger system (records game data). Safe for all users."); EnableCodex = Config.Bind<bool>("Core", "EnableCodex", true, "Turns on the Codex system (stores patch info). Safe for all users."); EnablePromotions = Config.Bind<bool>("Core", "EnablePromotions", true, "Allows the Eye to promote changes into the Codex. Safe unless you're debugging."); LedgerMaxSizeMB = Config.Bind<int>("Storage", "LedgerMaxSizeMB", 64, "How big the Ledger is allowed to get. Normal use: 5–20 MB. Heavy use: 20–60 MB. Extreme use: 100–300 MB. Expert dumps can push it higher. Default is safe."); CodexMaxSizeMB = Config.Bind<int>("Storage", "CodexMaxSizeMB", 32, "How big the Codex is allowed to get. Usually stays under 1 MB. Even heavy use rarely exceeds 3 MB. Default is more than enough."); EyeDumpMaxFileSizeKB = Config.Bind<int>("Storage", "EyeDumpMaxFileSizeKB", 5120, "Maximum size of normal dump files. Typical dumps: 200 KB – 3 MB. Prevents runaway file growth."); EyeDumpMaxFileSizeExpertKB = Config.Bind<int>("Storage", "EyeDumpMaxFileSizeExpertKB", 20480, "Maximum size of expert dumps. Expert dumps can reach 20–80 MB depending on settings. Do not raise above 100 MB unless you know what you're doing."); DeepDiagnostics = Config.Bind<bool>("Diagnostics", "DeepDiagnostics", false, "Extra logging and extra detail. Helps debugging. Slows things down."); LedgerDebug = Config.Bind<bool>("Diagnostics", "LedgerDebug", false, "Shows Ledger internals in the log. Only useful for developers."); CodexDebug = Config.Bind<bool>("Diagnostics", "CodexDebug", false, "Shows Codex internals in the log. Only useful for developers."); DumpAllFields = Config.Bind<bool>("Dumping", "DumpAllFields", false, "Shows more info about objects. Adds ~200–800 KB per dump."); DumpAllMethods = Config.Bind<bool>("Dumping", "DumpAllMethods", false, "Lists all functions on objects. Adds ~100–300 KB."); DumpAllProperties = Config.Bind<bool>("Dumping", "DumpAllProperties", false, "Lists all properties on objects. Adds ~200–500 KB."); DumpAllComponents = Config.Bind<bool>("Dumping", "DumpAllComponents", false, "Shows all components attached to objects. Adds 1–3 MB depending on scene complexity."); EnableExpertMode = Config.Bind<bool>("Expert", "EnableExpertMode", false, "Unlocks dangerous settings. Expert dumps can reach 20–200 MB. If you don't know what this means, don't touch it."); DumpAllFieldsExpert = Config.Bind<bool>("Expert", "DumpAllFieldsExpert", false, "Shows *every* value inside objects, even hidden ones. Adds 5–20 MB per dump. Slow."); DumpAllComponentsExpert = Config.Bind<bool>("Expert", "DumpAllComponentsExpert", false, "Shows *every* Unity component, even engine internals. Adds 20–80 MB per dump. Very slow."); DumpAllMethodsExpert = Config.Bind<bool>("Expert", "DumpAllMethodsExpert", false, "Lists every function, including hidden ones. Adds 1–5 MB."); DumpAllPropertiesExpert = Config.Bind<bool>("Expert", "DumpAllPropertiesExpert", false, "Lists every property, including hidden ones. Adds 1–5 MB."); } } internal static class BlackBoxLogger { private static ManualLogSource _log; internal static void Initialize(ManualLogSource log) { _log = log; } private static string Colorize(string message) { try { if (message.Contains("[Codex]")) { return "<color=#FF00FF>" + message + "</color>"; } if (message.Contains("[Diagnostics]") || message.Contains("dump_eye")) { return "<color=#00FFFF>" + message + "</color>"; } if (message.Contains("[Stable]") || message.Contains("[Adaptive]")) { return "<color=#00FF00>" + message + "</color>"; } if (message.Contains("[NeedsAttention]") || message.Contains("[Drift]")) { return "<color=#FFFF00>" + message + "</color>"; } if (message.Contains("[Failure]") || message.Contains("[Watchdog]") || message.Contains("[Unstable]") || message.Contains("[Oscillating]")) { return "<color=#FF0000>" + message + "</color>"; } return message; } catch { return message; } } internal static void Info(string message) { try { ManualLogSource log = _log; if (log != null) { log.LogInfo((object)Colorize("[BlackBox] " + message)); } } catch { } } internal static void Warn(string message) { try { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)Colorize("[BlackBox] " + message)); } } catch { } } internal static void Error(string message) { try { ManualLogSource log = _log; if (log != null) { log.LogError((object)Colorize("[BlackBox] " + message)); } } catch { } } internal static void MaskedError(string message) { try { ManualLogSource log = _log; if (log != null) { log.LogError((object)Colorize("[BlackBox] " + message)); } } catch { } } } internal static class BootSplash { private static ManualLogSource _logger; public static void Initialize(ManualLogSource logger) { _logger = logger ?? throw new ArgumentNullException("logger"); } public static void Render(HarmonyIntelligence.HarmonyTelemetry harmony, LedgerSnapshot ledger, CodexSnapshot codex, DumpSnapshot dump) { if (_logger == null) { throw new InvalidOperationException("BootSplash.Initialize must be called before Render."); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("┌──────────────────────────────────────────────────────────────┐"); stringBuilder.AppendLine("│ W U B A R R K ’ S E Y E │"); stringBuilder.AppendLine("│ THE EYE IS OPEN │"); stringBuilder.AppendLine("├──────────────────────────────────────────────────────────────┤"); stringBuilder.AppendLine($"│ Mod Enabled: {BlackBoxConfig.EnableMod.Value}"); stringBuilder.AppendLine("│ Physics Authority Mode: " + BlackBoxConfig.PhysicsAuthorityMode.Value); stringBuilder.AppendLine($"│ Expert Mode: {BlackBoxConfig.EnableExpertMode.Value}"); stringBuilder.AppendLine("├──────────────────────────────────────────────────────────────┤"); stringBuilder.AppendLine("│ Harmony Patching: │"); stringBuilder.AppendLine($"│ Patch Classes Found: {harmony?.PatchClassesFound ?? 0}"); stringBuilder.AppendLine($"│ Target Methods Matched: {harmony?.TargetMethodsMatched ?? 0}"); stringBuilder.AppendLine($"│ Patches Applied: {harmony?.PatchesApplied ?? 0}"); stringBuilder.AppendLine("├──────────────────────────────────────────────────────────────┤"); stringBuilder.AppendLine($"│ Ledger: {BlackBoxConfig.EnableLedger.Value}"); stringBuilder.AppendLine($"│ Ledger Size: {ledger.CurrentSizeMB} / {BlackBoxConfig.LedgerMaxSizeMB.Value} MB"); stringBuilder.AppendLine($"│ Ledger Debug: {BlackBoxConfig.LedgerDebug.Value}"); stringBuilder.AppendLine($"│ Evidence Files: {ledger.EvidenceCount}"); stringBuilder.AppendLine($"│ Aggregates: {ledger.AggregateCount}"); stringBuilder.AppendLine("│ Last Ingestion: " + ledger.LastIngestionTimestamp); stringBuilder.AppendLine("├──────────────────────────────────────────────────────────────┤"); stringBuilder.AppendLine($"│ Codex: {BlackBoxConfig.EnableCodex.Value}"); stringBuilder.AppendLine($"│ Promotions Enabled: {BlackBoxConfig.EnablePromotions.Value}"); stringBuilder.AppendLine($"│ Codex Size: {codex.CurrentSizeMB} / {BlackBoxConfig.CodexMaxSizeMB.Value} MB"); stringBuilder.AppendLine($"│ Codex Debug: {BlackBoxConfig.CodexDebug.Value}"); stringBuilder.AppendLine("│ Last Promotion: " + codex.LastPromotionTimestamp); stringBuilder.AppendLine("├──────────────────────────────────────────────────────────────┤"); stringBuilder.AppendLine("│ Eye Dump System: │"); stringBuilder.AppendLine($"│ Deep Diagnostics: {BlackBoxConfig.DeepDiagnostics.Value}"); stringBuilder.AppendLine($"│ Dump Flags: Fields={BlackBoxConfig.DumpAllFields.Value}, Methods={BlackBoxConfig.DumpAllMethods.Value}"); stringBuilder.AppendLine($"│ Props={BlackBoxConfig.DumpAllProperties.Value}, Comps={BlackBoxConfig.DumpAllComponents.Value}"); stringBuilder.AppendLine($"│ File Size Limit: {BlackBoxConfig.EyeDumpMaxFileSizeKB.Value} KB"); stringBuilder.AppendLine($"│ Expert Override: {BlackBoxConfig.EyeDumpMaxFileSizeExpertKB.Value} KB"); stringBuilder.AppendLine("│ Last Dump: " + dump.LastDumpTimestamp); stringBuilder.AppendLine("├──────────────────────────────────────────────────────────────┤"); stringBuilder.AppendLine("│ Status: All Systems Online │"); stringBuilder.AppendLine("│ The Eye is Open │"); stringBuilder.AppendLine("└──────────────────────────────────────────────────────────────┘"); _logger.LogInfo((object)stringBuilder.ToString()); } } public sealed class CodexRuntime { private readonly string _codexRootPath; private readonly int _maxSizeMB; private CodexSnapshot _lastSnapshot = CodexSnapshot.Empty(); public CodexSnapshot LastSnapshot => _lastSnapshot; public CodexRuntime(string codexRootPath, int maxSizeMB) { if (string.IsNullOrWhiteSpace(codexRootPath)) { throw new ArgumentException("Codex root path must not be null or empty.", "codexRootPath"); } _codexRootPath = codexRootPath; _maxSizeMB = ((maxSizeMB > 0) ? maxSizeMB : 0); Directory.CreateDirectory(_codexRootPath); } public CodexSnapshot BuildSnapshot(string lastPromotionTimestamp = null) { long num = 0L; if (Directory.Exists(_codexRootPath)) { string[] files = Directory.GetFiles(_codexRootPath, "*", SearchOption.AllDirectories); foreach (string fileName in files) { try { FileInfo fileInfo = new FileInfo(fileName); num += fileInfo.Length; } catch { } } } return _lastSnapshot = new CodexSnapshot((int)(num / 1048576), lastPromotionTimestamp ?? _lastSnapshot.LastPromotionTimestamp); } public bool IsAtOrAboveMaxSize() { if (_maxSizeMB <= 0) { return false; } return _lastSnapshot.CurrentSizeMB >= _maxSizeMB; } public void UpdateLastPromotionTimestamp(string timestamp) { string lastPromotionTimestamp = (string.IsNullOrWhiteSpace(timestamp) ? "n/a" : timestamp); _lastSnapshot = new CodexSnapshot(_lastSnapshot.CurrentSizeMB, lastPromotionTimestamp); } } internal static class DumpMLBuilder { private const string MlFileName = "dumpML.json"; public static void BuildAndWriteDump(ManualLogSource logger, string dumpRootPath, LedgerSnapshot ledgerSnapshot, DumpSnapshot dumpSnapshot, int codexMaxSizeMB = 0) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown if (logger == null) { throw new ArgumentNullException("logger"); } if (string.IsNullOrWhiteSpace(dumpRootPath)) { throw new ArgumentException("Dump root path must not be null or empty.", "dumpRootPath"); } try { Directory.CreateDirectory(dumpRootPath); } catch (Exception arg) { logger.LogError((object)$"[Eye/DumpML] Failed to ensure dump root directory '{dumpRootPath}': {arg}"); return; } try { logger.LogInfo((object)("[Eye/DumpML] Building Fort-Knox ML dump for '" + dumpRootPath + "' ...")); CodexSnapshot snapshot = BuildCodexSnapshotSafe(logger, codexMaxSizeMB); JObject val = new JObject { ["meta"] = (JToken)(object)BuildMetaSection(dumpRootPath), ["ledger"] = (JToken)(object)BuildLedgerSection(ledgerSnapshot), ["codex"] = (JToken)(object)BuildCodexSection(snapshot), ["dumpRuntime"] = (JToken)(object)BuildDumpRuntimeSection(dumpSnapshot), ["deep"] = (JToken)(object)BuildDeepSection(logger, dumpRootPath) }; string text = Path.Combine(dumpRootPath, "dumpML.json"); File.WriteAllText(text, ((JToken)val).ToString((Formatting)1)); logger.LogInfo((object)("[Eye/DumpML] Fort-Knox ML dump written to '" + text + "'.")); } catch (Exception arg2) { logger.LogError((object)$"[Eye/DumpML] Failed to build ML dump for '{dumpRootPath}': {arg2}"); } } private static JObject BuildMetaSection(string dumpRootPath) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown return new JObject { ["timestampUtc"] = JToken.op_Implicit(DateTime.UtcNow.ToString("u")), ["dumpRoot"] = JToken.op_Implicit(dumpRootPath) }; } private static JObject BuildLedgerSection(LedgerSnapshot snapshot) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown if (snapshot == null) { snapshot = LedgerSnapshot.Empty(); } return new JObject { ["currentSizeMB"] = JToken.op_Implicit(snapshot.CurrentSizeMB), ["evidenceCount"] = JToken.op_Implicit(snapshot.EvidenceCount), ["aggregateCount"] = JToken.op_Implicit(snapshot.AggregateCount), ["lastIngestionTimestamp"] = JToken.op_Implicit(snapshot.LastIngestionTimestamp ?? "n/a") }; } private static JObject BuildCodexSection(CodexSnapshot snapshot) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown if (snapshot == null) { snapshot = CodexSnapshot.Empty(); } return new JObject { ["currentSizeMB"] = JToken.op_Implicit(snapshot.CurrentSizeMB), ["lastPromotionTimestamp"] = JToken.op_Implicit(snapshot.LastPromotionTimestamp ?? "n/a") }; } private static JObject BuildDumpRuntimeSection(DumpSnapshot snapshot) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown if (snapshot == null) { snapshot = DumpSnapshot.Empty(); } return new JObject { ["lastDumpTimestamp"] = JToken.op_Implicit(snapshot.LastDumpTimestamp ?? "n/a") }; } private static JObject BuildDeepSection(ManualLogSource logger, string dumpRootPath) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown JObject val = new JObject(); AddRawTextIfExists(logger, val, dumpRootPath, "dump_meta", "dump_meta.txt"); AddRawTextIfExists(logger, val, dumpRootPath, "eye_dump", "eye_dump.txt"); AddJsonLinesIfExists(logger, val, dumpRootPath, "harmony_evidence", "harmony_evidence.jsonl"); return val; } private static void AddRawTextIfExists(ManualLogSource logger, JObject target, string dumpRootPath, string logicalKey, string fileName) { try { string path = Path.Combine(dumpRootPath, fileName); if (File.Exists(path)) { string text = File.ReadAllText(path); target[logicalKey] = JToken.op_Implicit(text); } } catch (Exception ex) { if (logger != null) { logger.LogWarning((object)("[Eye/DumpML] Failed to read raw text '" + fileName + "' for key '" + logicalKey + "': " + ex.Message)); } } } private static void AddJsonLinesIfExists(ManualLogSource logger, JObject target, string dumpRootPath, string logicalKey, string fileName) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown try { string path = Path.Combine(dumpRootPath, fileName); if (!File.Exists(path)) { return; } JArray val = new JArray(); foreach (string item in File.ReadLines(path)) { if (!string.IsNullOrWhiteSpace(item)) { try { val.Add(JToken.Parse(item)); } catch { val.Add(JToken.op_Implicit(item)); } } } target[logicalKey] = (JToken)(object)val; } catch (Exception ex) { if (logger != null) { logger.LogWarning((object)("[Eye/DumpML] Failed to read JSONL '" + fileName + "' for key '" + logicalKey + "': " + ex.Message)); } } } private static CodexSnapshot BuildCodexSnapshotSafe(ManualLogSource logger, int codexMaxSizeMB) { try { return new CodexRuntime(Path.Combine(Paths.ConfigPath, "WubarrksEye", "Codex"), codexMaxSizeMB).BuildSnapshot() ?? CodexSnapshot.Empty(); } catch (Exception ex) { if (logger != null) { logger.LogWarning((object)("[Eye/DumpML] Failed to build Codex snapshot: " + ex.Message)); } return CodexSnapshot.Empty(); } } } internal static class DumpRuntime { private static ManualLogSource _logger; private static readonly string DumpRootPath = Path.Combine(Paths.ConfigPath, "WubarrksEye", "Dumps"); private static readonly string MetaFilePath = Path.Combine(DumpRootPath, "dump_meta.txt"); public static void Initialize(ManualLogSource logger) { _logger = logger ?? throw new ArgumentNullException("logger"); EnsureDirectory(); _logger.LogInfo((object)"[Eye/Dump] DumpRuntime initialized."); } public static DumpSnapshot BuildSnapshot() { try { EnsureDirectory(); return new DumpSnapshot(ReadMetaTimestampSafe(MetaFilePath)); } catch (Exception arg) { ManualLogSource logger = _logger; if (logger != null) { logger.LogError((object)$"[Eye/Dump] Failed to build DumpSnapshot: {arg}"); } return DumpSnapshot.Empty(); } } public static void UpdateLastDumpTimestamp(DateTime utcNow) { try { EnsureDirectory(); File.WriteAllText(MetaFilePath, utcNow.ToString("u")); } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[Eye/Dump] Failed to write dump meta file '" + MetaFilePath + "': " + ex.Message)); } } } private static void EnsureDirectory() { try { if (!Directory.Exists(DumpRootPath)) { Directory.CreateDirectory(DumpRootPath); } } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[Eye/Dump] Failed to create directory '" + DumpRootPath + "': " + ex.Message)); } } } private static string ReadMetaTimestampSafe(string metaFile) { try { if (!File.Exists(metaFile)) { return "n/a"; } string text = File.ReadAllText(metaFile).Trim(); if (string.IsNullOrEmpty(text)) { return "n/a"; } return text; } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[Eye/Dump] Failed to read dump meta file '" + metaFile + "': " + ex.Message)); } return "n/a"; } } } internal static class DumpUtils { public static string CreateNewDumpRoot() { string text = Path.Combine(Paths.ConfigPath, "WubarrksEye", "Dumps"); Directory.CreateDirectory(text); string path = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"); string text2 = Path.Combine(text, path); Directory.CreateDirectory(text2); BlackBoxLogger.Info("[Eye] Created new dump directory: " + text2); return text2; } public static void SafeCall(string label, string dumpRoot, Action action) { try { BlackBoxLogger.Info("[Eye] Dumping " + label + "..."); action(); BlackBoxLogger.Info("[Eye] " + label + " dump complete."); } catch (Exception ex) { BlackBoxLogger.Warn("[Eye] " + label + " dump failed: " + ex.Message); WriteTextFile(dumpRoot, label + "_ERROR.txt", "Subsystem '" + label + "' failed:\n" + ex.Message); } } public static void WriteTextFile(string folder, string fileName, string content) { try { Directory.CreateDirectory(folder); string path = Path.Combine(folder, fileName); int num = (BlackBoxConfig.EnableExpertMode.Value ? BlackBoxConfig.EyeDumpMaxFileSizeExpertKB.Value : BlackBoxConfig.EyeDumpMaxFileSizeKB.Value); int num2 = num * 1024; byte[] bytes = Encoding.UTF8.GetBytes(content); if (bytes.Length > num2) { BlackBoxLogger.Warn($"[Eye] File '{fileName}' exceeded size limit ({num} KB). Truncating."); byte[] array = new byte[num2]; Array.Copy(bytes, array, num2); File.WriteAllBytes(path, array); } else { File.WriteAllBytes(path, bytes); } } catch (Exception ex) { BlackBoxLogger.Error("[Eye] Failed to write file '" + fileName + "': " + ex.Message); } } public static string EnsureSubfolder(string root, string name) { string text = Path.Combine(root, name); Directory.CreateDirectory(text); return text; } } internal static class EyeCommands { private static ManualLogSource _logger; public static void Initialize(ManualLogSource logger) { _logger = logger ?? throw new ArgumentNullException("logger"); RegisterCommand("dump_eye", DumpEye); RegisterCommand("dump_eye_deep", DumpEyeDeep); RegisterCommand("dump_eye_target", DumpEyeTarget); RegisterCommand("dump_eye_api_all", DumpEyeApiAll); _logger.LogInfo((object)"[Eye/Commands] EyeCommands initialized."); } private static void RegisterCommand(string name, Action<string[]> handler) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) try { new ConsoleCommand(name, "Wubarrk's Eye: " + name, (ConsoleEvent)delegate(ConsoleEventArgs args) { handler(args.Args); }, 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 DumpEye(string[] args) { try { _logger.LogInfo((object)"[Eye/Commands] dump_eye invoked."); EyeDumpSystem.Run(Path.Combine(Paths.ConfigPath, "WubarrksEye", "Dumps"), new string[1] { "basic" }); } catch (Exception arg) { _logger.LogError((object)$"[Eye/Commands] dump_eye failed: {arg}"); } } private static void DumpEyeTarget(string[] args) { try { if (!BlackBoxConfig.EnableExpertMode.Value) { _logger.LogWarning((object)"[Eye/Commands] dump_eye_target requires Expert Mode."); return; } if (args == null || args.Length == 0) { _logger.LogWarning((object)"[Eye/Commands] dump_eye_target requires a target name."); return; } string text = args[0]; _logger.LogInfo((object)("[Eye/Commands] dump_eye_target invoked for: " + text)); EyeDumpSystem.Run(Path.Combine(Paths.ConfigPath, "WubarrksEye", "Dumps"), new string[1] { "deep" }); AppendTargetToLatestDump(text); } catch (Exception arg) { _logger.LogError((object)$"[Eye/Commands] dump_eye_target failed: {arg}"); } } private static void AppendTargetToLatestDump(string target) { try { string path = Path.Combine(Paths.ConfigPath, "WubarrksEye", "Dumps"); string path2 = Path.Combine(path, "dump_id.txt"); if (!File.Exists(path2)) { _logger.LogWarning((object)"[Eye/Commands] No dump_id.txt found; cannot append target."); return; } if (!int.TryParse(File.ReadAllText(path2).Trim(), out var result)) { _logger.LogWarning((object)"[Eye/Commands] Invalid dump_id.txt; cannot append target."); return; } int num = result - 1; string path3 = Path.Combine(Path.Combine(path, $"Dump_{num:D4}"), "dump_meta.txt"); if (!File.Exists(path3)) { _logger.LogWarning((object)"[Eye/Commands] No dump_meta.txt found; cannot append target."); return; } File.AppendAllText(path3, "\nTarget=" + target); _logger.LogInfo((object)$"[Eye/Commands] Target '{target}' appended to dump {num}."); } catch (Exception ex) { _logger.LogWarning((object)("[Eye/Commands] Failed to append target: " + ex.Message)); } } private static void DumpEyeDeep(string[] args) { try { if (!BlackBoxConfig.EnableExpertMode.Value) { _logger.LogWarning((object)"[Eye/Commands] dump_eye_deep requires Expert Mode."); return; } _logger.LogInfo((object)"[Eye/Commands] dump_eye_deep invoked."); EyeDumpSystem.Run(Path.Combine(Paths.ConfigPath, "WubarrksEye", "Dumps"), new string[1] { "deep" }); } catch (Exception arg) { _logger.LogError((object)$"[Eye/Commands] dump_eye_deep failed: {arg}"); } } private static void DumpEyeApiAll(string[] args) { try { if (!BlackBoxConfig.EnableExpertMode.Value) { _logger.LogWarning((object)"[Eye/Commands] dump_eye_api_all requires Expert Mode."); return; } _logger.LogInfo((object)"[Eye/Commands] dump_eye_api_all invoked."); string text = Path.Combine(Paths.ConfigPath, "WubarrksEye", "Dumps"); Directory.CreateDirectory(text); DumpApiAll.RunApiAll(text); _logger.LogInfo((object)"[Eye/Commands] dump_eye_api_all completed."); } catch (Exception arg) { _logger.LogError((object)$"[Eye/Commands] dump_eye_api_all failed: {arg}"); } } } internal static class EyeDumpNotifier { private static ManualLogSource _logger; private static AbyssalLedgerRuntime _ledgerRuntime; public static void Initialize(ManualLogSource logger, AbyssalLedgerRuntime ledgerRuntime) { _logger = logger ?? throw new ArgumentNullException("logger"); _ledgerRuntime = ledgerRuntime ?? throw new ArgumentNullException("ledgerRuntime"); _logger.LogInfo((object)"[Eye/Notifier] EyeDumpNotifier initialized."); } public static void NotifyDumpCreated(int dumpId, string dumpFolderPath) { if (dumpId <= 0) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)$"[Eye/Notifier] NotifyDumpCreated called with invalid dumpId={dumpId}. Ignoring."); } return; } if (string.IsNullOrEmpty(dumpFolderPath)) { ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)$"[Eye/Notifier] NotifyDumpCreated called with null/empty dumpFolderPath for dumpId={dumpId}. Ignoring."); } return; } try { DateTime utcNow = DateTime.UtcNow; DumpRuntime.UpdateLastDumpTimestamp(utcNow); _ledgerRuntime.IngestDump(dumpId, dumpFolderPath); LedgerRuntime.UpdateLastIngestionTimestamp(utcNow); CodexBootstrapper.RefreshSnapshot(); ManualLogSource logger3 = _logger; if (logger3 != null) { logger3.LogInfo((object)$"[Eye/Notifier] Dump {dumpId} ingested and Codex snapshot refreshed successfully."); } } catch (Exception arg) { ManualLogSource logger4 = _logger; if (logger4 != null) { logger4.LogError((object)$"[Eye/Notifier] NotifyDumpCreated failed for dumpId={dumpId}: {arg}"); } } } } internal static class EyeDumpSystem { public static void Run(string dumpRoot, string[] args) { try { if (args.Length == 0) { BlackBoxLogger.Info("Usage: dump_eye <basic|runtime|api|deep>"); return; } string text = args[0].ToLowerInvariant(); switch (text) { case "basic": DumpBasic(dumpRoot); break; case "runtime": DumpRuntime(dumpRoot); break; case "api": DumpApi(dumpRoot); break; case "deep": DumpItDeep.RunDeep(dumpRoot, args); break; default: BlackBoxLogger.Warn("Unknown dump mode: " + text); break; } } catch (Exception arg) { BlackBoxLogger.Error($"[EyeDumpSystem] Dump failed: {arg}"); } } private static void DumpBasic(string dumpRoot) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) try { using StreamWriter streamWriter = new StreamWriter(Path.Combine(dumpRoot, "BasicDump.txt"), append: false); streamWriter.WriteLine("=== BASIC DUMP ==="); streamWriter.WriteLine("Unity Version: " + Application.unityVersion); streamWriter.WriteLine($"Platform: {Application.platform}"); streamWriter.WriteLine("Product: " + Application.productName); streamWriter.WriteLine("Company: " + Application.companyName); streamWriter.WriteLine("Version: " + Application.version); streamWriter.WriteLine("=================="); BlackBoxLogger.Info("[EyeDumpSystem] Basic dump complete."); } catch (Exception arg) { BlackBoxLogger.Error($"[EyeDumpSystem] Basic dump failed: {arg}"); } } private static void DumpRuntime(string dumpRoot) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) try { using StreamWriter streamWriter = new StreamWriter(Path.Combine(dumpRoot, "RuntimeDump.txt"), append: false); streamWriter.WriteLine("=== RUNTIME DUMP ==="); streamWriter.WriteLine($"Time: {DateTime.Now}"); Scene activeScene = SceneManager.GetActiveScene(); streamWriter.WriteLine("Scene: " + ((Scene)(ref activeScene)).name); streamWriter.WriteLine("===================="); BlackBoxLogger.Info("[EyeDumpSystem] Runtime dump complete."); } catch (Exception arg) { BlackBoxLogger.Error($"[EyeDumpSystem] Runtime dump failed: {arg}"); } } private static void DumpApi(string dumpRoot) { try { using StreamWriter streamWriter = new StreamWriter(Path.Combine(dumpRoot, "ApiDump.txt"), append: false); streamWriter.WriteLine("=== API DUMP ==="); streamWriter.WriteLine("This mode is deprecated. Use: dump_eye deep"); streamWriter.WriteLine("================"); BlackBoxLogger.Info("[EyeDumpSystem] API dump complete."); } catch (Exception arg) { BlackBoxLogger.Error($"[EyeDumpSystem] API dump failed: {arg}"); } } } internal static class FieldMapCache { private static readonly Dictionary<Type, List<FieldInfo>> _fieldCache = new Dictionary<Type, List<FieldInfo>>(); private static readonly Dictionary<Type, List<PropertyInfo>> _propertyCache = new Dictionary<Type, List<PropertyInfo>>(); private static readonly Dictionary<Type, List<MethodInfo>> _methodCache = new Dictionary<Type, List<MethodInfo>>(); internal static List<FieldInfo> GetFields(Type t) { if (t == null) { return new List<FieldInfo>(); } if (_fieldCache.TryGetValue(t, out List<FieldInfo> value)) { return value; } List<FieldInfo> list = SafeBuildFieldList(t); _fieldCache[t] = list; return list; } internal static List<PropertyInfo> GetProperties(Type t) { if (t == null) { return new List<PropertyInfo>(); } if (_propertyCache.TryGetValue(t, out List<PropertyInfo> value)) { return value; } List<PropertyInfo> list = SafeBuildPropertyList(t); _propertyCache[t] = list; return list; } internal static List<MethodInfo> GetMethods(Type t) { if (t == null) { return new List<MethodInfo>(); } if (_methodCache.TryGetValue(t, out List<MethodInfo> value)) { return value; } List<MethodInfo> list = SafeBuildMethodList(t); _methodCache[t] = list; return list; } private static List<FieldInfo> SafeBuildFieldList(Type t) { try { return new List<FieldInfo>(t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); } catch { return new List<FieldInfo>(); } } private static List<PropertyInfo> SafeBuildPropertyList(Type t) { try { return new List<PropertyInfo>(t.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); } catch { return new List<PropertyInfo>(); } } private static List<MethodInfo> SafeBuildMethodList(Type t) { try { return new List<MethodInfo>(t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); } catch { return new List<MethodInfo>(); } } } internal static class HarmonyEvidenceIngestor { private static ManualLogSource _logger; public static void Initialize(ManualLogSource logger) { _logger = logger ?? throw new ArgumentNullException("logger"); _logger.LogInfo((object)"[Eye/HarmonyEvidence] HarmonyEvidenceIngestor initialized."); } public static void WriteHarmonyEvidence(int dumpId, string dumpFolderPath) { if (dumpId <= 0) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)$"[Eye/HarmonyEvidence] WriteHarmonyEvidence called with invalid dumpId={dumpId}. Ignoring."); } return; } if (string.IsNullOrEmpty(dumpFolderPath)) { ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)$"[Eye/HarmonyEvidence] WriteHarmonyEvidence called with null/empty dumpFolderPath for dumpId={dumpId}. Ignoring."); } return; } try { HarmonyIntelligence.HarmonyTelemetry lastSnapshot = HarmonyIntelligence.GetLastSnapshot(); if (lastSnapshot == null) { ManualLogSource logger3 = _logger; if (logger3 != null) { logger3.LogWarning((object)"[Eye/HarmonyEvidence] No Harmony telemetry available; skipping Harmony evidence."); } return; } using (StreamWriter streamWriter = new StreamWriter(Path.Combine(dumpFolderPath, "harmony_evidence.jsonl"), append: false, Encoding.UTF8)) { string value = BuildSummaryJson(dumpId, lastSnapshot); streamWriter.WriteLine(value); foreach (string patchedMethod in lastSnapshot.PatchedMethods) { string value2 = BuildPatchedMethodJson(dumpId, patchedMethod); streamWriter.WriteLine(value2); } foreach (string missingTarget in lastSnapshot.MissingTargets) { string value3 = BuildMissingTargetJson(dumpId, missingTarget); streamWriter.WriteLine(value3); } foreach (string conflict in lastSnapshot.Conflicts) { string value4 = BuildConflictJson(dumpId, conflict); streamWriter.WriteLine(value4); } } ManualLogSource logger4 = _logger; if (logger4 != null) { logger4.LogInfo((object)$"[Eye/HarmonyEvidence] Harmony evidence written for dump {dumpId}."); } } catch (Exception arg) { ManualLogSource logger5 = _logger; if (logger5 != null) { logger5.LogError((object)$"[Eye/HarmonyEvidence] WriteHarmonyEvidence failed for dumpId={dumpId}: {arg}"); } } } private static string BuildSummaryJson(int dumpId, HarmonyIntelligence.HarmonyTelemetry telemetry) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{"); stringBuilder.AppendFormat("\"DumpId\":{0}", dumpId); stringBuilder.Append(",\"Type\":\"Summary\""); stringBuilder.AppendFormat(",\"PatchClassesFound\":{0}", telemetry.PatchClassesFound); stringBuilder.AppendFormat(",\"TargetMethodsMatched\":{0}", telemetry.TargetMethodsMatched); stringBuilder.AppendFormat(",\"PatchesApplied\":{0}", telemetry.PatchesApplied); stringBuilder.Append("}"); return stringBuilder.ToString(); } private static string BuildPatchedMethodJson(int dumpId, string methodSignature) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{"); stringBuilder.AppendFormat("\"DumpId\":{0}", dumpId); stringBuilder.Append(",\"Type\":\"PatchedMethod\""); stringBuilder.AppendFormat(",\"MethodSignature\":\"{0}\"", EscapeJsonString(methodSignature)); stringBuilder.Append("}"); return stringBuilder.ToString(); } private static string BuildMissingTargetJson(int dumpId, string patchClass) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{"); stringBuilder.AppendFormat("\"DumpId\":{0}", dumpId); stringBuilder.Append(",\"Type\":\"MissingTarget\""); stringBuilder.AppendFormat(",\"PatchClass\":\"{0}\"", EscapeJsonString(patchClass)); stringBuilder.Append("}"); return stringBuilder.ToString(); } private static string BuildConflictJson(int dumpId, string conflictDescription) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{"); stringBuilder.AppendFormat("\"DumpId\":{0}", dumpId); stringBuilder.Append(",\"Type\":\"Conflict\""); stringBuilder.AppendFormat(",\"ConflictDescription\":\"{0}\"", EscapeJsonString(conflictDescription)); stringBuilder.Append("}"); return stringBuilder.ToString(); } private static string EscapeJsonString(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } return value.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r") .Replace("\n", "\\n") .Replace("\t", "\\t"); } } internal static class HarmonyIntelligence { internal sealed class HarmonyTelemetry { public int PatchClassesFound { get; } public int TargetMethodsMatched { get; } public int PatchesApplied { get; } public IReadOnlyList<string> PatchedMethods { get; } public IReadOnlyList<string> MissingTargets { get; } public IReadOnlyList<string> Conflicts { get; } public HarmonyTelemetry(int patchClassesFound, int targetMethodsMatched, int patchesApplied, IReadOnlyList<string> patchedMethods, IReadOnlyList<string> missingTargets, IReadOnlyList<string> conflicts) { PatchClassesFound = patchClassesFound; TargetMethodsMatched = targetMethodsMatched; PatchesApplied = patchesApplied; PatchedMethods = patchedMethods ?? Array.Empty<string>(); MissingTargets = missingTargets ?? Array.Empty<string>(); Conflicts = conflicts ?? Array.Empty<string>(); } } private sealed class TargetResolutionResult { public List<MethodBase> MatchedMethods { get; } = new List<MethodBase>(); public List<string> MissingTargets { get; } = new List<string>(); } private static readonly string PatchNamespacePrefix = "BlackBox"; private static ManualLogSource _logger; private static Harmony _harmony; private static HarmonyTelemetry _lastSnapshot; public static void Initialize(Harmony harmony, ManualLogSource logger) { _harmony = harmony ?? throw new ArgumentNullException("harmony"); _logger = logger ?? throw new ArgumentNullException("logger"); _logger.LogInfo((object)"[Eye/Harmony] HarmonyIntelligence initialized."); } public static HarmonyTelemetry CaptureSnapshot() { if (_harmony == null) { throw new InvalidOperationException("HarmonyIntelligence.Initialize must be called before CaptureSnapshot."); } try { List<Type> list = FindPatchClasses(); int count = list.Count; TargetResolutionResult targetResolutionResult = ResolveTargets(list); int count2 = targetResolutionResult.MatchedMethods.Count; int count3 = targetResolutionResult.MissingTargets.Count; List<MethodBase> obj = Harmony.GetAllPatchedMethods()?.ToList() ?? new List<MethodBase>(); int count4 = obj.Count; List<string> patchedMethods = (from s in obj.Where((MethodBase m) => m != null).Select(FormatMethodSignature) orderby s select s).ToList(); List<string> source = DetectConflicts(obj); HarmonyTelemetry harmonyTelemetry = (_lastSnapshot = new HarmonyTelemetry(count, count2, count4, patchedMethods, targetResolutionResult.MissingTargets.OrderBy((string s) => s).ToList(), source.OrderBy((string s) => s).ToList())); LogSummary(harmonyTelemetry, count3); return harmonyTelemetry; } catch (Exception arg) { ManualLogSource logger = _logger; if (logger != null) { logger.LogError((object)$"[Eye/Harmony] Failed to capture Harmony snapshot: {arg}"); } return _lastSnapshot = new HarmonyTelemetry(0, 0, 0, Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>()); } } public static HarmonyTelemetry GetLastSnapshot() { return _lastSnapshot; } private static List<Type> FindPatchClasses() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); List<Type> list = new List<Type>(); Type[] array = types; foreach (Type type in array) { if ((string.IsNullOrEmpty(PatchNamespacePrefix) || type.FullName.StartsWith(PatchNamespacePrefix, StringComparison.Ordinal)) && type.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Any()) { list.Add(type); } } return list; } private static TargetResolutionResult ResolveTargets(List<Type> patchClasses) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) TargetResolutionResult targetResolutionResult = new TargetResolutionResult(); foreach (Type patchClass in patchClasses) { try { List<MethodInfo> list = new PatchClassProcessor(_harmony, patchClass).Patch(); if (list == null || list.Count == 0) { targetResolutionResult.MissingTargets.Add(patchClass.FullName ?? patchClass.Name); continue; } foreach (MethodInfo item in list) { if (item != null) { targetResolutionResult.MatchedMethods.Add(item); } } } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[Eye/Harmony] Failed to resolve targets for patch class " + patchClass.FullName + ": " + ex.Message)); } targetResolutionResult.MissingTargets.Add(patchClass.FullName ?? patchClass.Name); } } return targetResolutionResult; } private static List<string> DetectConflicts(List<MethodBase> patchedMethods) { List<string> list = new List<string>(); foreach (MethodBase patchedMethod in patchedMethods) { if (patchedMethod == null) { continue; } try { Patches patchInfo = Harmony.GetPatchInfo(patchedMethod); if (patchInfo != null) { ReadOnlyCollection<string> owners = patchInfo.Owners; if (owners != null && owners.Count > 1) { string text = FormatMethodSignature(patchedMethod); string text2 = string.Join(", ", owners); list.Add(text + " :: Owners=[" + text2 + "]"); } } } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[Eye/Harmony] Failed to inspect conflict for method " + FormatMethodSignature(patchedMethod) + ": " + ex.Message)); } } } return list; } private static string FormatMethodSignature(MethodBase method) { if (method == null) { return "<null>"; } string text = ((method.DeclaringType != null) ? method.DeclaringType.FullName : "<NoType>"); ParameterInfo[] parameters = method.GetParameters(); string text2 = string.Join(", ", parameters.Select((ParameterInfo p) => p.ParameterType.Name)); return text + "." + method.Name + "(" + text2 + ")"; } private static void LogSummary(HarmonyTelemetry telemetry, int missingTargetsCount) { if (_logger != null) { _logger.LogInfo((object)"[Eye/Harmony] Harmony telemetry captured:"); _logger.LogInfo((object)$"[Eye/Harmony] Patch classes found: {telemetry.PatchClassesFound}"); _logger.LogInfo((object)$"[Eye/Harmony] Target methods matched: {telemetry.TargetMethodsMatched}"); _logger.LogInfo((object)$"[Eye/Harmony] Patches applied: {telemetry.PatchesApplied}"); _logger.LogInfo((object)$"[Eye/Harmony] Missing targets: {missingTargetsCount}"); _logger.LogInfo((object)$"[Eye/Harmony] Conflicts: {telemetry.Conflicts.Count}"); } } } internal static class LedgerRuntime { private static ManualLogSource _logger; internal static readonly string LedgerRootPath = Path.Combine(Paths.ConfigPath, "WubarrksEye", "Ledger"); private static readonly string EvidencePath = Path.Combine(LedgerRootPath, "Evidence"); private static readonly string AggregatesPath = Path.Combine(LedgerRootPath, "Aggregates"); private static readonly string MetaFilePath = Path.Combine(LedgerRootPath, "ledger_meta.txt"); public static void Initialize(ManualLogSource logger) { _logger = logger ?? throw new ArgumentNullException("logger"); EnsureDirectories(); _logger.LogInfo((object)"[Eye/Ledger] LedgerRuntime initialized."); } public static LedgerSnapshot BuildSnapshot() { try { EnsureDirectories(); int currentSizeMB = ComputeDirectorySizeMB(LedgerRootPath); int evidenceCount = CountFilesSafe(EvidencePath); int aggregateCount = CountFilesSafe(AggregatesPath); string lastIngestionTimestamp = ReadMetaTimestampSafe(MetaFilePath); return new LedgerSnapshot(currentSizeMB, evidenceCount, aggregateCount, lastIngestionTimestamp); } catch (Exception arg) { ManualLogSource logger = _logger; if (logger != null) { logger.LogError((object)$"[Eye/Ledger] Failed to build LedgerSnapshot: {arg}"); } return LedgerSnapshot.Empty(); } } public static void UpdateLastIngestionTimestamp(DateTime utcNow) { try { EnsureDirectories(); File.WriteAllText(MetaFilePath, utcNow.ToString("u")); } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[Eye/Ledger] Failed to write Ledger meta file '" + MetaFilePath + "': " + ex.Message)); } } } private static void EnsureDirectories() { TryCreateDirectory(LedgerRootPath); TryCreateDirectory(EvidencePath); TryCreateDirectory(AggregatesPath); } private static void TryCreateDirectory(string path) { try { if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[Eye/Ledger] Failed to create directory '" + path + "': " + ex.Message)); } } } private static int ComputeDirectorySizeMB(string path) { try { if (!Directory.Exists(path)) { return 0; } long num = 0L; foreach (FileInfo item in new DirectoryInfo(path).EnumerateFiles("*", SearchOption.AllDirectories)) { num += item.Length; } long num2 = 1048576L; long num3 = num / num2; if (num3 > int.MaxValue) { return int.MaxValue; } return (int)num3; } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[Eye/Ledger] Failed to compute directory size for '" + path + "': " + ex.Message)); } return 0; } } private static int CountFilesSafe(string path) { try { if (!Directory.Exists(path)) { return 0; } return Directory.GetFiles(path, "*", SearchOption.AllDirectories).Length; } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[Eye/Ledger] Failed to count files in '" + path + "': " + ex.Message)); } return 0; } } private static string ReadMetaTimestampSafe(string metaFile) { try { if (!File.Exists(metaFile)) { return "n/a"; } string text = File.ReadAllText(metaFile).Trim(); if (string.IsNullOrEmpty(text)) { return "n/a"; } return text; } catch (Exception ex) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[Eye/Ledger] Failed to read Ledger meta file '" + metaFile + "': " + ex.Message)); } return "n/a"; } } } internal static class ReflectionUtils { internal static Dictionary<string, string> ExtractFields(object instance) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); if (instance == null) { return dictionary; } foreach (FieldInfo field in FieldMapCache.GetFields(instance.GetType())) { try { object value = field.GetValue(instance); dictionary[field.Name] = SafeString(value); } catch { dictionary[field.Name] = "[unavailable]"; } } return dictionary; } internal static Dictionary<string, string> ExtractProperties(object instance) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); if (instance == null) { return dictionary; } foreach (PropertyInfo property in FieldMapCache.GetProperties(instance.GetType())) { try { if (property.GetIndexParameters().Length != 0) { dictionary[property.Name] = "[indexer]"; continue; } object value = property.GetValue(instance, null); dictionary[property.Name] = SafeString(value); } catch { dictionary[property.Name] = "[unavailable]"; } } return dictionary; } internal static List<string> ExtractMethodSignatures(object instance) { List<string> list = new List<string>(); if (instance == null) { return list; } foreach (MethodInfo method in FieldMapCache.GetMethods(instance.GetType())) { try { list.Add(FormatMethodSignature(method)); } catch { list.Add("[unavailable method]"); } } return list; } private static string SafeString(object value) { if (value == null) { return "null"; } try { return value.ToString(); } catch { return "[unstringifiable]"; } } private static string FormatMethodSignature(MethodInfo m) { string text = m.ReturnType?.Name ?? "void"; string name = m.Name; ParameterInfo[] parameters = m.GetParameters(); List<string> list = new List<string>(); ParameterInfo[] array = parameters; foreach (ParameterInfo parameterInfo in array) { try { string text2 = parameterInfo.ParameterType?.Name ?? "unknown"; list.Add(text2 + " " + parameterInfo.Name); } catch { list.Add("unknown_param"); } } return text + " " + name + "(" + string.Join(", ", list) + ")"; } } public sealed class LedgerSnapshot { public int CurrentSizeMB { get; } public int EvidenceCount { get; } public int AggregateCount { get; } public string LastIngestionTimestamp { get; } public LedgerSnapshot(int currentSizeMB, int evidenceCount, int aggregateCount, string lastIngestionTimestamp) { CurrentSizeMB = currentSizeMB; EvidenceCount = evidenceCount; AggregateCount = aggregateCount; LastIngestionTimestamp = lastIngestionTimestamp ?? "n/a"; } public static LedgerSnapshot Empty() { return new LedgerSnapshot(0, 0, 0, "n/a"); } } public sealed class CodexSnapshot { public int CurrentSizeMB { get; } public string LastPromotionTimestamp { get; } public CodexSnapshot(int currentSizeMB, string lastPromotionTimestamp) { CurrentSizeMB = currentSizeMB; LastPromotionTimestamp = lastPromotionTimestamp ?? "n/a"; } public static CodexSnapshot Empty() { return new CodexSnapshot(0, "n/a"); } } public sealed class DumpSnapshot { public string LastDumpTimestamp { get; } public DumpSnapshot(string lastDumpTimestamp) { LastDumpTimestamp = lastDumpTimestamp ?? "n/a"; } public static DumpSnapshot Empty() { return new DumpSnapshot("n/a"); } } internal static class TypeInspector { internal static void DumpTypes(string outputFolder, string fileName, IEnumerable<Type> types, string title) { if (types == null) { return; } Directory.CreateDirectory(outputFolder); string text = Path.Combine(outputFolder, fileName); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# " + title); stringBuilder.AppendLine($"# Generated at {DateTime.Now:O}"); stringBuilder.AppendLine(); int num = 0; int num2 = 0; foreach (Type item in from t in types where t != null orderby t.FullName select t) { if (DumpSingleType(stringBuilder, item)) { num++; } else { num2++; } } if (num2 > 0) { stringBuilder.AppendLine(); stringBuilder.AppendLine($"# Note: Some types could not be fully inspected ({num2} failures)."); stringBuilder.AppendLine("# This does not affect the integrity of the successfully captured data."); } File.WriteAllText(text, stringBuilder.ToString(), n