Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ModDoctor v1.1.0
ModDoctor.dll
Decompiled 2 months 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.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Profiling; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace ModDoctor; [BepInPlugin("bub.moddoctor", "Mod Doctor", "1.1.0")] public class ModDoctorPlugin : BaseUnityPlugin { public enum ReportLanguage { Auto, English, Portuguese } private class PlayerMods { public string Name; public DateTime When; public List<ModDifference> Diff; } public const string Guid = "bub.moddoctor"; public const string Version = "1.1.0"; private const string ReportRpc = "ModDoctor_Report"; private const string HelloRpc = "ModDoctor_Hello"; private const string DiffRpc = "ModDoctor_Diff"; private const string AdminRequestRpc = "ModDoctor_AdminRequest"; private const string AdminDataRpc = "ModDoctor_AdminData"; internal static ModDoctorPlugin Instance; internal static ManualLogSource Log; private ConfigEntry<ReportLanguage> language; private ConfigEntry<KeyboardShortcut> toggleKey; private ConfigEntry<bool> showToast; private ConfigEntry<bool> suppressRepeats; private ConfigEntry<int> suppressAfter; private ConfigEntry<bool> checkUpdates; private ConfigEntry<int> updateCacheHours; private ConfigEntry<bool> sendToServer; private ConfigEntry<bool> collectFromClients; private ConfigEntry<string> serverOnlyMods; internal Diagnosis Diagnosis; private RepeatFilter repeatFilter; private UpdateChecker updates; private LoadTimer loadTimer; private readonly Health health = new Health(); private string outputDir; private List<InstalledMod> installed; private List<string> duplicates; private float nextReportWrite; private int lastWrittenVersion = -1; private float nextSend; private int lastSentVersion = -1; private ZRoutedRpc registeredRpc; private bool helloSent; private float nextHello; private List<ModDifference> serverDiff; private bool serverIsAdmin; private AdminData adminData; private float adminRequestedAt = -100f; private bool diffToastPending; private readonly Dictionary<string, PlayerMods> playerMods = new Dictionary<string, PlayerMods>(); private bool windowOpen; private int tab; private Rect windowRect = new Rect(60f, 60f, 860f, 640f); private Vector2 scroll; private float nextWindowRefresh; private TabContext view; private readonly HashSet<string> expanded = new HashSet<string>(); private string toastText; private float toastUntil; private float nextToastCheck; private bool wasInWorld; private readonly HashSet<string> announced = new HashSet<string>(); private GUIStyle toastStyle; private List<KeyValuePair<string, int>> topPrefabs = new List<KeyValuePair<string, int>>(); private float nextObjectsRefresh; private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; language = ((BaseUnityPlugin)this).Config.Bind<ReportLanguage>("General", "Language", ReportLanguage.Auto, "Report language. Auto follows the game language (Portuguese or English)."); toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)288, (KeyCode[])(object)new KeyCode[0]), "Opens and closes the report window."); showToast = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowToast", true, "Show a short notice when a mod starts causing problems."); suppressRepeats = ((BaseUnityPlugin)this).Config.Bind<bool>("Log", "SuppressRepeats", true, "Stop identical errors from being written to LogOutput.log over and over. A summary line is written instead."); suppressAfter = ((BaseUnityPlugin)this).Config.Bind<int>("Log", "SuppressAfter", 20, "How many identical copies are written before the rest are suppressed."); checkUpdates = ((BaseUnityPlugin)this).Config.Bind<bool>("Updates", "CheckThunderstore", true, "Look up the latest version of each installed package on thunderstore.io (public API, no personal data sent)."); updateCacheHours = ((BaseUnityPlugin)this).Config.Bind<int>("Updates", "CacheHours", 12, "How long a Thunderstore lookup is reused before asking again."); sendToServer = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "SendReportsToServer", true, "Send your findings (installed mods, versions and errors, with your character name) to the server you are playing on, if it runs Mod Doctor."); collectFromClients = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "CollectClientReports", true, "On a server: store the reports players send, in BepInEx/ModDoctor/players and summary.txt."); serverOnlyMods = ((BaseUnityPlugin)this).Config.Bind<string>("Server", "ServerOnlyMods", "ArgusMagnus-ServersideQoL*, Smootheim-*, MidnightMods-NetworkPerformanceSystem", "On a server: mod folders that players do not need (comma separated, * wildcard). They are not reported as missing."); outputDir = Path.Combine(Paths.BepInExRootPath, "ModDoctor"); Directory.CreateDirectory(outputDir); Diagnosis = new Diagnosis(); Application.logMessageReceivedThreaded += new LogCallback(OnUnityLog); Logger.Listeners.Add((ILogListener)(object)new ModErrorListener(Diagnosis)); loadTimer = new LoadTimer(); Logger.Listeners.Add((ILogListener)(object)loadTimer); if (suppressRepeats.Value) { repeatFilter = RepeatFilter.Install(suppressAfter.Value); } updates = new UpdateChecker(Path.Combine(outputDir, "thunderstore-cache.txt")); health.ResetGcWindow(); Log.LogInfo((object)("Mod Doctor 1.1.0 watching for mod errors. Report: " + Path.Combine(outputDir, "report.txt"))); } private void Start() { Diagnosis.IndexPlugins(); Backfill.FromLogOutput(Path.Combine(Paths.BepInExRootPath, "LogOutput.log"), Diagnosis); try { installed = Inventory.Scan(); } catch (Exception ex) { installed = new List<InstalledMod>(); Log.LogWarning((object)("Mod scan failed: " + ex.Message)); } try { duplicates = Inventory.Duplicates(); } catch (Exception) { duplicates = new List<string>(); } foreach (string duplicate in duplicates) { Log.LogWarning((object)("Installed twice: " + duplicate)); } if (checkUpdates.Value) { ((MonoBehaviour)this).StartCoroutine(updates.Run(Diagnosis.Packages(), updateCacheHours.Value)); } } private void OnDestroy() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Application.logMessageReceivedThreaded -= new LogCallback(OnUnityLog); WriteReport(force: true); } private void OnApplicationQuit() { WriteReport(force: true); } private void OnUnityLog(string condition, string stackTrace, LogType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if ((int)type == 4 || (int)type == 0 || (int)type == 1) { long timestamp = Stopwatch.GetTimestamp(); Diagnosis.Record(condition, stackTrace, null); Interlocked.Increment(ref health.ErrorsSeen); Interlocked.Add(ref health.OwnTicks, Stopwatch.GetTimestamp() - timestamp); } } private void Update() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) long timestamp = Stopwatch.GetTimestamp(); bool flag = IsHeadless(); if (flag || windowOpen) { health.Sample(Time.unscaledDeltaTime); } Diagnosis.ResolvePending(); if (!flag) { UpdateToasts(); } if (!flag) { KeyboardShortcut value = toggleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { windowOpen = !windowOpen; if (windowOpen) { health.ResetGcWindow(); nextWindowRefresh = 0f; } } } if (windowOpen && Time.unscaledTime >= nextWindowRefresh) { RefreshWindow(); } if (repeatFilter != null) { repeatFilter.FlushSummaries(); } if (Time.unscaledTime >= nextReportWrite) { nextReportWrite = Time.unscaledTime + 30f; WriteReport(force: false); } UpdateNetworking(); health.OwnFrames++; Interlocked.Add(ref health.OwnTicks, Stopwatch.GetTimestamp() - timestamp); } private void UpdateToasts() { //IL_00c6: 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_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) if (!showToast.Value || Time.unscaledTime < nextToastCheck) { return; } nextToastCheck = Time.unscaledTime + 2f; if (!((Object)(object)Player.m_localPlayer != (Object)null)) { wasInWorld = false; return; } if (diffToastPending && Time.unscaledTime >= toastUntil) { diffToastPending = false; int num = serverDiff.Count((ModDifference d) => d.Kind != "extra"); toastText = Text.T((num == 1) ? "toastdiff1" : "toastdiff", Lang()).Replace("{n}", num.ToString()).Replace("{key}", ((object)toggleKey.Value/*cast due to .constrained prefix*/).ToString()); toastUntil = Time.unscaledTime + 12f; return; } List<string> list = new List<string>(); HashSet<string> hashSet = new HashSet<string>(); foreach (Problem item in Diagnosis.Snapshot()) { if (item.Mod == null) { continue; } string text = ReportWriter.Kind(item); if (!(text == "error")) { hashSet.Add(item.Mod.Name); if (announced.Add(item.Mod.Name + "|" + text) && wasInWorld && !list.Contains(item.Mod.Name)) { list.Add(item.Mod.Name); } } } List<string> list2 = (wasInWorld ? list : hashSet.ToList()); wasInWorld = true; if (list2.Count != 0 && !(Time.unscaledTime < toastUntil - 2f)) { string newValue = string.Join(", ", list2.Take(3).ToArray()) + ((list2.Count > 3) ? (" +" + (list2.Count - 3)) : ""); toastText = Text.T((list2.Count == 1) ? "toast" : "toastmany", Lang()).Replace("{mod}", newValue).Replace("{key}", ((object)toggleKey.Value/*cast due to .constrained prefix*/).ToString()); toastUntil = Time.unscaledTime + 12f; } } private static bool IsHeadless() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 return (int)SystemInfo.graphicsDeviceType == 4; } internal string Lang() { if (language.Value == ReportLanguage.English) { return "en"; } if (language.Value == ReportLanguage.Portuguese) { return "pt"; } try { if (Localization.instance != null && Localization.instance.GetSelectedLanguage().StartsWith("Portuguese")) { return "pt"; } } catch (Exception) { } return "en"; } private bool OnDedicatedServerAsClient() { if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { return ZNet.instance.GetServerPeer() != null; } return false; } private string BuildReport(bool rich) { return ReportWriter.Render(Diagnosis.Snapshot(), updates, Diagnosis.PluginCount, Lang(), null, rich); } private void WriteReport(bool force) { int version = Diagnosis.Version; if (!force && version == lastWrittenVersion) { return; } lastWrittenVersion = version; try { File.WriteAllText(Path.Combine(outputDir, "report.txt"), BuildReport(rich: false), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZNet.instance.IsDedicated() && collectFromClients.Value) { ServerStore.Save(outputDir, "(server)", "1.1.0", Diagnosis.PluginCount, ReportWriter.Serialize(Diagnosis.Snapshot(), updates, 40), Lang()); } } catch (Exception ex) { Log.LogWarning((object)("Could not write report: " + ex.Message)); } } private void UpdateNetworking() { //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Expected O, but got Unknown //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown ZRoutedRpc instance = ZRoutedRpc.instance; if (instance == null || (Object)(object)ZNet.instance == (Object)null) { return; } if (registeredRpc != instance) { instance.Register<ZPackage>("ModDoctor_Report", (Action<long, ZPackage>)OnClientReport); instance.Register<ZPackage>("ModDoctor_Hello", (Action<long, ZPackage>)OnHello); instance.Register<ZPackage>("ModDoctor_Diff", (Action<long, ZPackage>)OnDiff); instance.Register<ZPackage>("ModDoctor_AdminRequest", (Action<long, ZPackage>)OnAdminRequest); instance.Register<ZPackage>("ModDoctor_AdminData", (Action<long, ZPackage>)OnAdminData); registeredRpc = instance; lastSentVersion = -1; helloSent = false; serverDiff = null; serverIsAdmin = false; adminData = null; } if (ZNet.instance.IsServer() || !sendToServer.Value) { return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer == null || (Object)(object)Game.instance == (Object)null || Game.instance.GetPlayerProfile() == null) { return; } string name = Game.instance.GetPlayerProfile().GetName(); if (!helloSent && Time.unscaledTime >= nextHello && installed != null) { nextHello = Time.unscaledTime + 5f; ZPackage val = new ZPackage(); val.Write(1); val.Write(name); val.Write("1.1.0"); val.Write(Inventory.Serialize(installed)); instance.InvokeRoutedRPC(serverPeer.m_uid, "ModDoctor_Hello", new object[1] { val }); helloSent = true; } if (!(Time.unscaledTime < nextSend)) { nextSend = Time.unscaledTime + 60f; int version = Diagnosis.Version; if (version != lastSentVersion) { ZPackage val2 = new ZPackage(); val2.Write(1); val2.Write(name); val2.Write("1.1.0"); val2.Write(Diagnosis.PluginCount); val2.Write(ReportWriter.Serialize(Diagnosis.Snapshot(), updates, 40)); instance.InvokeRoutedRPC(serverPeer.m_uid, "ModDoctor_Report", new object[1] { val2 }); lastSentVersion = version; } } } private bool IsServerSide() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } private bool SenderIsAdmin(long sender) { ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null || peer.m_socket == null) { return false; } return ZNet.instance.IsAdmin(peer.m_socket.GetHostName()); } private void OnClientReport(long sender, ZPackage pkg) { if (!IsServerSide() || !collectFromClients.Value) { return; } try { int num = pkg.ReadInt(); if (num == 1) { string player = pkg.ReadString(); string clientVersion = pkg.ReadString(); int plugins = pkg.ReadInt(); string text = pkg.ReadString(); if (text.Length > 64000) { text = text.Substring(0, 64000); } ServerStore.Save(outputDir, player, clientVersion, plugins, text, Lang()); } } catch (Exception ex) { Log.LogWarning((object)("Ignored a malformed report from peer " + sender + ": " + ex.Message)); } } private void OnHello(long sender, ZPackage pkg) { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown if (!IsServerSide()) { return; } try { if (pkg.ReadInt() == 1) { string text = pkg.ReadString(); pkg.ReadString(); List<InstalledMod> player = Inventory.Parse(pkg.ReadString()); List<ModDifference> list = ModCompare.Compare(player, installed ?? new List<InstalledMod>(), serverOnlyMods.Value.Split(',')); PlayerMods playerMods = new PlayerMods(); playerMods.Name = text; playerMods.When = DateTime.Now; playerMods.Diff = list; lock (this.playerMods) { this.playerMods[text] = playerMods; } if (collectFromClients.Value) { ServerStore.SaveMods(outputDir, text, ModCompare.Serialize(list), Lang()); } ZPackage val = new ZPackage(); val.Write(1); val.Write(SenderIsAdmin(sender)); val.Write(ModCompare.Serialize(list)); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "ModDoctor_Diff", new object[1] { val }); } } catch (Exception ex) { Log.LogWarning((object)("Ignored a malformed mod list from peer " + sender + ": " + ex.Message)); } } private void OnDiff(long sender, ZPackage pkg) { if (IsServerSide()) { return; } try { if (pkg.ReadInt() == 1) { serverIsAdmin = pkg.ReadBool(); serverDiff = ModCompare.Parse(pkg.ReadString()); if (serverDiff.Any((ModDifference d) => d.Kind != "extra")) { diffToastPending = true; } nextWindowRefresh = 0f; } } catch (Exception ex) { Log.LogWarning((object)("Ignored a malformed answer from the server: " + ex.Message)); } } private void OnAdminRequest(long sender, ZPackage pkg) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown if (IsServerSide()) { AdminData obj; if (!SenderIsAdmin(sender)) { AdminData adminData = new AdminData(); adminData.NotAdmin = true; obj = adminData; } else { obj = BuildAdminData(); } AdminData adminData2 = obj; string text = adminData2.Serialize(); if (text.Length > 60000) { text = text.Substring(0, 60000); } ZPackage val = new ZPackage(); val.Write(2); val.Write(text); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "ModDoctor_AdminData", new object[1] { val }); } } private void OnAdminData(long sender, ZPackage pkg) { if (IsServerSide()) { return; } try { if (pkg.ReadInt() == 2) { adminData = AdminData.Parse(pkg.ReadString()); nextWindowRefresh = 0f; } } catch (Exception) { } } private void RequestAdminOverview() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown ZNetPeer val = (((Object)(object)ZNet.instance == (Object)null) ? null : ZNet.instance.GetServerPeer()); if (val != null && ZRoutedRpc.instance != null && !(Time.unscaledTime - adminRequestedAt < 5f)) { adminRequestedAt = Time.unscaledTime; ZPackage val2 = new ZPackage(); val2.Write(1); val2.Write(Lang()); ZRoutedRpc.instance.InvokeRoutedRPC(val.m_uid, "ModDoctor_AdminRequest", new object[1] { val2 }); } } private AdminData BuildAdminData() { AdminData adminData = new AdminData(); adminData.Uptime = Health.Uptime(DateTime.Now - health.Started); adminData.Fps = health.AverageFps(); adminData.FpsLow = health.LowFps(); adminData.MemoryMb = (double)GC.GetTotalMemory(forceFullCollection: false) / 1048576.0; adminData.Objects = WorldObjects.TotalKnown(); List<ZNetPeer> peers = ZNet.instance.GetPeers(); adminData.Online = peers.Count; List<string> list = (from p in peers select p.m_playerName into n where !string.IsNullOrEmpty(n) select n).ToList(); foreach (string item in list) { adminData.Get(item).Online = true; } lock (playerMods) { foreach (PlayerMods value in playerMods.Values) { AdminData.AdminPlayer adminPlayer = adminData.Get(value.Name); adminPlayer.HasModList = true; adminPlayer.Diffs = value.Diff.Where((ModDifference d) => d.Kind != "extra").ToList(); } } foreach (KeyValuePair<string, List<string[]>> item2 in ServerStore.ProblemRows(outputDir)) { adminData.Get(item2.Key).Problems = item2.Value; } return adminData; } private void RefreshWindow() { nextWindowRefresh = Time.unscaledTime + 1f; TabContext tabContext = new TabContext(); tabContext.Lang = Lang(); tabContext.Problems = Diagnosis.Snapshot(); tabContext.Updates = updates; tabContext.Packages = Diagnosis.Packages().ToList(); tabContext.Connected = OnDedicatedServerAsClient(); tabContext.ServerDiff = serverDiff; tabContext.Duplicates = duplicates ?? new List<string>(); tabContext.LoadTimes = loadTimer.Times(); tabContext.PluginCount = Diagnosis.PluginCount; tabContext.InstalledCount = ((installed != null) ? installed.Count : 0); tabContext.Health = health; tabContext.InWorld = (Object)(object)ZNetScene.instance != (Object)null; if (tab == 2 && tabContext.InWorld && Time.unscaledTime >= nextObjectsRefresh) { nextObjectsRefresh = Time.unscaledTime + 3f; topPrefabs = WorldObjects.TopPrefabs(15); } tabContext.TopPrefabs = topPrefabs; tabContext.ObjectsLoaded = WorldObjects.Loaded(); tabContext.ObjectsKnown = WorldObjects.TotalKnown(); if (tab == 3 && adminData == null) { RequestAdminOverview(); } tabContext.Admin = adminData; tabContext.Expanded = expanded; view = tabContext; } private void OnGUI() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Expected O, but got Unknown //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Expected O, but got Unknown //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) if (!IsHeadless() && ((toastText != null && !(Time.unscaledTime >= toastUntil)) || windowOpen)) { long timestamp = Stopwatch.GetTimestamp(); Theme.Init(); if (toastStyle == null) { toastStyle = new GUIStyle(Theme.CardBox); toastStyle.font = Theme.Body.font; toastStyle.fontSize = 15; toastStyle.wordWrap = true; toastStyle.richText = true; toastStyle.alignment = (TextAnchor)3; toastStyle.padding = new RectOffset(14, 14, 10, 10); toastStyle.normal.textColor = Theme.Gold; Log.LogInfo((object)("Window fonts: title " + (((Object)(object)Theme.Title.font == (Object)null) ? "default" : ((Object)Theme.Title.font).name) + ", body " + (((Object)(object)Theme.Body.font == (Object)null) ? "default" : ((Object)Theme.Body.font).name))); Log.LogDebug((object)("Fonts available: " + Theme.FontReport())); } if (toastText != null && Time.unscaledTime < toastUntil) { float num = toastStyle.CalcHeight(new GUIContent(toastText), 460f); GUI.Box(new Rect(20f, 20f, 460f, num), toastText, toastStyle); } if (windowOpen && view != null) { windowRect = GUILayout.Window(19780, windowRect, new WindowFunction(DrawWindow), "", Theme.Window, (GUILayoutOption[])(object)new GUILayoutOption[0]); } Interlocked.Add(ref health.OwnTicks, Stopwatch.GetTimestamp() - timestamp); } } private void DrawWindow(int id) { //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_03f8: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_0448: Unknown result type (might be due to invalid IL or missing references) TabContext tabContext = view; string lang = tabContext.Lang; GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("MOD DOCTOR", Theme.Title, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUILayout.Space(10f); GUILayout.Label("1.1.0", Theme.Version, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(false), GUILayout.Height(28f) }); GUILayout.FlexibleSpace(); if (GUILayout.Button("X", Theme.Button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(34f) })) { windowOpen = false; } GUILayout.EndHorizontal(); GUILayout.Space(6f); int n = (from p in tabContext.Problems where p.Mod != null && p.Kind != "engine" select p.Mod.Name).Distinct().Count(); int n2 = ((tabContext.ServerDiff != null) ? (tabContext.ServerDiff.Count((ModDifference d) => d.Kind != "extra") + tabContext.Duplicates.Count) : 0); List<string> list = new List<string>(); list.Add(Text.T("tab_problems", lang) + Badge(n, "#D9534F")); list.Add(Text.T("tab_mods", lang) + Badge(n2, "#F0A050")); list.Add(Text.T("tab_perf", lang)); List<string> list2 = list; if (tabContext.Connected && (serverIsAdmin || ZNet.instance.LocalPlayerIsAdminOrHost())) { list2.Add(Text.T("tab_server", lang)); } if (tab >= list2.Count) { tab = 0; } GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); for (int num = 0; num < list2.Count; num++) { if (GUILayout.Button(list2[num], (num == tab) ? Theme.TabActive : Theme.Tab, (GUILayoutOption[])(object)new GUILayoutOption[0]) && num != tab) { tab = num; scroll = Vector2.zero; if (tab == 3) { adminData = null; } nextWindowRefresh = 0f; } } GUILayout.EndHorizontal(); GUILayout.Space(8f); scroll = GUILayout.BeginScrollView(scroll, (GUILayoutOption[])(object)new GUILayoutOption[0]); switch (tab) { case 0: Tabs.Problems(tabContext); break; case 1: Tabs.Mods(tabContext); break; case 2: Tabs.Performance(tabContext); break; case 3: Tabs.Server(tabContext); break; } GUILayout.EndScrollView(); GUILayout.Space(6f); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (tab == 0 && GUILayout.Button(Text.T("copy", lang), Theme.Button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) })) { GUIUtility.systemCopyBuffer = BuildReport(rich: false); } if (tab == 3 && GUILayout.Button(Text.T("refresh", lang), Theme.Button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) })) { adminData = null; nextWindowRefresh = 0f; } if (GUILayout.Button(Text.T("folder", lang), Theme.Button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) })) { Application.OpenURL("file://" + outputDir.Replace('\\', '/')); } GUILayout.FlexibleSpace(); GUILayout.Label(Text.T("footer", lang).Replace("{key}", ((object)toggleKey.Value/*cast due to .constrained prefix*/).ToString()), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUILayout.EndHorizontal(); GUI.DragWindow(new Rect(0f, 0f, 10000f, 44f)); } private static string Badge(int n, string color) { if (n > 0) { return " <color=" + color + ">" + n + "</color>"; } return ""; } } public class InstalledMod { public string Id; public string Version; public override string ToString() { return Id + " " + Version; } } public static class Inventory { public static List<InstalledMod> Scan() { List<InstalledMod> list = new List<InstalledMod>(); string pluginPath = Paths.PluginPath; if (!Directory.Exists(pluginPath)) { return list; } Dictionary<string, string> dictionary = PluginVersionsByFolder(pluginPath); string[] directories = Directory.GetDirectories(pluginPath); foreach (string text in directories) { if (Directory.GetFiles(text, "*.dll", SearchOption.AllDirectories).Length == 0) { continue; } InstalledMod installedMod = new InstalledMod(); installedMod.Id = Path.GetFileName(text); string path = Path.Combine(text, "manifest.json"); if (File.Exists(path)) { Match match = Regex.Match(File.ReadAllText(path), "\"version_number\"\\s*:\\s*\"([^\"]+)\""); if (match.Success) { installedMod.Version = match.Groups[1].Value; } } if (installedMod.Version == null) { dictionary.TryGetValue(installedMod.Id, out var value); installedMod.Version = value ?? "?"; } list.Add(installedMod); } string[] files = Directory.GetFiles(pluginPath, "*.dll"); foreach (string path2 in files) { InstalledMod installedMod2 = new InstalledMod(); installedMod2.Id = Path.GetFileNameWithoutExtension(path2); dictionary.TryGetValue(installedMod2.Id, out var value2); installedMod2.Version = value2 ?? "?"; list.Add(installedMod2); } return list.OrderBy<InstalledMod, string>((InstalledMod m) => m.Id, StringComparer.OrdinalIgnoreCase).ToList(); } private static Dictionary<string, string> PluginVersionsByFolder(string root) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); string fullPath = Path.GetFullPath(root); foreach (PluginInfo value in Chainloader.PluginInfos.Values) { if (string.IsNullOrEmpty(value.Location)) { continue; } string fullPath2 = Path.GetFullPath(value.Location); if (fullPath2.StartsWith(fullPath, StringComparison.OrdinalIgnoreCase)) { string text = fullPath2.Substring(fullPath.Length).TrimStart('\\', '/'); int num = text.IndexOfAny(new char[2] { '\\', '/' }); string key = ((num < 0) ? Path.GetFileNameWithoutExtension(text) : text.Substring(0, num)); if (!dictionary.ContainsKey(key)) { dictionary[key] = value.Metadata.Version.ToString(); } } } return dictionary; } public static string Serialize(List<InstalledMod> mods) { StringBuilder stringBuilder = new StringBuilder(); foreach (InstalledMod mod in mods) { stringBuilder.Append(mod.Id).Append('\t').Append(mod.Version) .Append('\n'); } return stringBuilder.ToString(); } public static List<InstalledMod> Parse(string text) { List<InstalledMod> list = new List<InstalledMod>(); string[] array = text.Split('\n'); foreach (string text2 in array) { string[] array2 = text2.Split('\t'); if (array2.Length >= 2 && array2[0].Length != 0) { InstalledMod installedMod = new InstalledMod(); installedMod.Id = array2[0]; installedMod.Version = array2[1].Trim(); list.Add(installedMod); } } return list; } public static List<string> Duplicates() { List<string> list = new List<string>(); string pluginPath = Paths.PluginPath; if (!Directory.Exists(pluginPath)) { return list; } HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (PluginInfo value2 in Chainloader.PluginInfos.Values) { if ((Object)(object)value2.Instance != (Object)null) { hashSet.Add(((object)value2.Instance).GetType().Assembly.GetName().Name); } } Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase); string fullPath = Path.GetFullPath(pluginPath); string[] files = Directory.GetFiles(pluginPath, "*.dll", SearchOption.AllDirectories); foreach (string text in files) { string name; try { name = AssemblyName.GetAssemblyName(text).Name; } catch (Exception) { continue; } if (hashSet.Contains(name)) { string text2 = Path.GetFullPath(text).Substring(fullPath.Length).TrimStart('\\', '/'); int num = text2.IndexOfAny(new char[2] { '\\', '/' }); string item = ((num < 0) ? ("plugins/" + text2) : text2.Substring(0, num)); if (!dictionary.TryGetValue(name, out var value)) { value = (dictionary[name] = new List<string>()); } if (!value.Contains(item)) { value.Add(item); } } } foreach (KeyValuePair<string, List<string>> item2 in dictionary) { if (item2.Value.Count > 1) { list.Add(item2.Key + ": " + string.Join(", ", item2.Value.ToArray())); } } return list; } } public class ModDifference { public string Kind; public string Id; public string PlayerVersion; public string ServerVersion; } public static class ModCompare { public static List<ModDifference> Compare(List<InstalledMod> player, List<InstalledMod> server, string[] serverOnly) { Dictionary<string, InstalledMod> dictionary = ToMap(player); Dictionary<string, InstalledMod> dictionary2 = ToMap(server); List<ModDifference> list = new List<ModDifference>(); foreach (InstalledMod value2 in dictionary2.Values) { if (!dictionary.TryGetValue(value2.Id, out var value)) { if (!Matches(value2.Id, serverOnly)) { list.Add(Diff("missing", value2.Id, null, value2.Version)); } } else if (value.Version != value2.Version) { list.Add(Diff("version", value2.Id, value.Version, value2.Version)); } } foreach (InstalledMod value3 in dictionary.Values) { if (!dictionary2.ContainsKey(value3.Id)) { list.Add(Diff("extra", value3.Id, value3.Version, null)); } } return (from d in list orderby (!(d.Kind == "missing")) ? ((d.Kind == "version") ? 1 : 2) : 0, d.Id select d).ToList(); } private static Dictionary<string, InstalledMod> ToMap(List<InstalledMod> mods) { Dictionary<string, InstalledMod> dictionary = new Dictionary<string, InstalledMod>(StringComparer.OrdinalIgnoreCase); foreach (InstalledMod mod in mods) { dictionary[mod.Id] = mod; } return dictionary; } private static ModDifference Diff(string kind, string id, string pv, string sv) { ModDifference modDifference = new ModDifference(); modDifference.Kind = kind; modDifference.Id = id; modDifference.PlayerVersion = pv; modDifference.ServerVersion = sv; return modDifference; } public static bool Matches(string id, string[] patterns) { foreach (string text in patterns) { string text2 = text.Trim(); if (text2.Length != 0) { string pattern = "^" + Regex.Escape(text2).Replace("\\*", ".*") + "$"; if (Regex.IsMatch(id, pattern, RegexOptions.IgnoreCase)) { return true; } } } return false; } public static string Serialize(List<ModDifference> diffs) { StringBuilder stringBuilder = new StringBuilder(); foreach (ModDifference diff in diffs) { stringBuilder.Append(diff.Kind).Append('\t').Append(diff.Id) .Append('\t') .Append(diff.PlayerVersion ?? "") .Append('\t') .Append(diff.ServerVersion ?? "") .Append('\n'); } return stringBuilder.ToString(); } public static List<ModDifference> Parse(string text) { List<ModDifference> list = new List<ModDifference>(); string[] array = text.Split('\n'); foreach (string text2 in array) { string[] array2 = text2.Split('\t'); if (array2.Length >= 4) { list.Add(Diff(array2[0], array2[1], (array2[2].Length == 0) ? null : array2[2], (array2[3].Trim().Length == 0) ? null : array2[3].Trim())); } } return list; } public static string Render(List<ModDifference> diffs, string lang, bool rich) { StringBuilder stringBuilder = new StringBuilder(); List<ModDifference> list = diffs.Where((ModDifference d) => d.Kind == "missing").ToList(); List<ModDifference> list2 = diffs.Where((ModDifference d) => d.Kind == "version").ToList(); List<ModDifference> list3 = diffs.Where((ModDifference d) => d.Kind == "extra").ToList(); if (list.Count == 0 && list2.Count == 0) { stringBuilder.Append(Color(Text.T("diff_ok", lang), "#8FE08F", rich)).Append('\n'); } if (list.Count > 0) { stringBuilder.Append(Color(Text.T("diff_missing", lang), "#FFA366", rich)).Append('\n'); foreach (ModDifference item in list) { stringBuilder.Append(" - ").Append(item.Id).Append(' ') .Append(item.ServerVersion) .Append('\n'); } } if (list2.Count > 0) { stringBuilder.Append(Color(Text.T("diff_version", lang), "#FFA366", rich)).Append('\n'); foreach (ModDifference item2 in list2) { stringBuilder.Append(" - ").Append(item2.Id).Append(": ") .Append(Text.T("yours", lang)) .Append(' ') .Append(item2.PlayerVersion) .Append(", ") .Append(Text.T("server", lang)) .Append(' ') .Append(item2.ServerVersion) .Append('\n'); } } if (list3.Count > 0) { stringBuilder.Append(Color(Text.T("diff_extra", lang), "#A8A29A", rich)).Append('\n'); foreach (ModDifference item3 in list3) { stringBuilder.Append(" - ").Append(item3.Id).Append(' ') .Append(item3.PlayerVersion) .Append('\n'); } } return stringBuilder.ToString(); } private static string Color(string text, string color, bool rich) { if (!rich) { return text; } return "<b><color=" + color + ">" + text + "</color></b>"; } } internal class LoadTimer : ILogListener, IDisposable { private static readonly Regex Loading = new Regex("^Loading \\[(.+?)\\s+([\\d\\.]+)\\]"); private readonly Stopwatch clock = Stopwatch.StartNew(); private readonly List<KeyValuePair<string, double>> times = new List<KeyValuePair<string, double>>(); private string current; private double currentStart; private bool done; public bool Done => done; public void LogEvent(object sender, LogEventArgs e) { if (done || e.Data == null) { return; } string text = ((e.Source == null) ? "" : e.Source.SourceName); if (!(text != "BepInEx")) { string text2 = e.Data.ToString(); double totalSeconds = clock.Elapsed.TotalSeconds; Match match = Loading.Match(text2); if (match.Success) { Close(totalSeconds); current = match.Groups[1].Value; currentStart = totalSeconds; } else if (text2.StartsWith("Chainloader startup complete")) { Close(totalSeconds); done = true; } } } private void Close(double now) { if (current != null) { lock (times) { times.Add(new KeyValuePair<string, double>(current, now - currentStart)); } current = null; } } public List<KeyValuePair<string, double>> Times() { lock (times) { return times.ToList(); } } public void Dispose() { } } public class Health { private readonly float[] frames = new float[600]; private int count; private int next; private int[] gcBaseline = new int[3]; private DateTime gcBaselineAt = DateTime.Now; public readonly DateTime Started = DateTime.Now; public long OwnTicks; public long OwnFrames; public long ErrorsSeen; public int SampleCount => count; public void Sample(float deltaTime) { frames[next] = deltaTime; next = (next + 1) % frames.Length; if (count < frames.Length) { count++; } } public void ResetGcWindow() { for (int i = 0; i < 3; i++) { gcBaseline[i] = GC.CollectionCount(i); } gcBaselineAt = DateTime.Now; } public double AverageFps() { if (count == 0) { return 0.0; } double num = 0.0; for (int i = 0; i < count; i++) { num += (double)frames[i]; } if (!(num <= 0.0)) { return (double)count / num; } return 0.0; } public double LowFps() { if (count < 20) { return 0.0; } float[] source = (from f in frames.Take(count) orderby f descending select f).ToArray(); int num = Math.Max(1, count / 100); double num2 = source.Take(num).Average((Func<float, double>)((float f) => f)); if (!(num2 <= 0.0)) { return 1.0 / num2; } return 0.0; } public double WorstFrameMs() { if (count == 0) { return 0.0; } return (double)frames.Take(count).Max() * 1000.0; } public double[] GcPerMinute() { double num = Math.Max(1.0 / 60.0, (DateTime.Now - gcBaselineAt).TotalMinutes); double[] array = new double[3]; for (int i = 0; i < 3; i++) { array[i] = (double)(GC.CollectionCount(i) - gcBaseline[i]) / num; } return array; } public double OwnMsPerFrame() { if (OwnFrames != 0) { return (double)OwnTicks * 1000.0 / (double)Stopwatch.Frequency / (double)OwnFrames; } return 0.0; } public double OwnMsTotal() { return (double)OwnTicks * 1000.0 / (double)Stopwatch.Frequency; } public static string Mb(long bytes) { return ((double)bytes / 1048576.0).ToString("0") + " MB"; } public static string Uptime(TimeSpan t) { return (int)t.TotalHours + "h" + t.Minutes.ToString("00") + "m"; } } public static class WorldObjects { private static FieldInfo instancesField; public static int TotalKnown() { if (ZDOMan.instance != null) { return ZDOMan.instance.NrOfObjects(); } return 0; } public static int Loaded() { if (!((Object)(object)ZNetScene.instance == (Object)null)) { return ZNetScene.instance.NrOfInstances(); } return 0; } public static List<KeyValuePair<string, int>> TopPrefabs(int max) { List<KeyValuePair<string, int>> result = new List<KeyValuePair<string, int>>(); if ((Object)(object)ZNetScene.instance == (Object)null) { return result; } if (instancesField == null) { instancesField = AccessTools.Field(typeof(ZNetScene), "m_instances"); } IDictionary dictionary = ((instancesField == null) ? null : (instancesField.GetValue(ZNetScene.instance) as IDictionary)); if (dictionary == null) { return result; } Dictionary<string, int> dictionary2 = new Dictionary<string, int>(); foreach (object value2 in dictionary.Values) { ZNetView val = (ZNetView)((value2 is ZNetView) ? value2 : null); if (!((Object)(object)val == (Object)null)) { string text = ((Object)((Component)val).gameObject).name; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num > 0) { text = text.Substring(0, num); } dictionary2.TryGetValue(text, out var value); dictionary2[text] = value + 1; } } return dictionary2.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).Take(max).ToList(); } } public static class Theme { public static readonly Color Gold = Hex("E8C170"); public static readonly Color GoldDim = Hex("9C7A45"); public static readonly Color Text = Hex("EDE3D0"); public static readonly Color Muted = Hex("D2C6B2"); public static readonly Color Soft = Hex("C9BCA6"); public static readonly Color Red = Hex("D9534F"); public static readonly Color Orange = Hex("F0A050"); public static readonly Color Yellow = Hex("E6C84A"); public static readonly Color Green = Hex("7FCF7F"); public static readonly Color Blue = Hex("7FB2E5"); public static readonly Color Slate = Hex("8A94A6"); private static readonly Color PanelTop = Hex("2A2016"); private static readonly Color PanelBottom = Hex("15100B"); private static readonly Color Card = Hex("2E2419"); private static readonly Color Border = Hex("6B5230"); public static GUIStyle Window; public static GUIStyle Title; public static GUIStyle Version; public static GUIStyle Tab; public static GUIStyle TabActive; public static GUIStyle CardBox; public static GUIStyle CardTitle; public static GUIStyle Body; public static GUIStyle Small; public static GUIStyle Mono; public static GUIStyle Hint; public static GUIStyle Chip; public static GUIStyle TileBox; public static GUIStyle TileValue; public static GUIStyle TileLabel; public static GUIStyle Button; public static GUIStyle Section; public static GUIStyle Banner; public static Texture2D White; private static bool ready; private static readonly Stack<Color> strips = new Stack<Color>(); public static Color Hex(string hex) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) Color result = default(Color); ColorUtility.TryParseHtmlString("#" + hex, ref result); return result; } public static void Init() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Expected O, but got Unknown //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Expected O, but got Unknown //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Expected O, but got Unknown //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Expected O, but got Unknown //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Expected O, but got Unknown //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Expected O, but got Unknown //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Expected O, but got Unknown //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_034b: Expected O, but got Unknown //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Expected O, but got Unknown //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03cf: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Expected O, but got Unknown //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Expected O, but got Unknown //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Expected O, but got Unknown //IL_0472: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Expected O, but got Unknown //IL_049c: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Expected O, but got Unknown //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04ca: Expected O, but got Unknown //IL_04d5: Unknown result type (might be due to invalid IL or missing references) //IL_04df: Expected O, but got Unknown //IL_04e8: Unknown result type (might be due to invalid IL or missing references) //IL_04f2: Expected O, but got Unknown //IL_04f5: Unknown result type (might be due to invalid IL or missing references) //IL_0508: Unknown result type (might be due to invalid IL or missing references) //IL_0522: Unknown result type (might be due to invalid IL or missing references) //IL_052c: Expected O, but got Unknown //IL_0583: Unknown result type (might be due to invalid IL or missing references) //IL_05a1: Unknown result type (might be due to invalid IL or missing references) //IL_05a6: Unknown result type (might be due to invalid IL or missing references) //IL_05a7: Unknown result type (might be due to invalid IL or missing references) //IL_05ae: Unknown result type (might be due to invalid IL or missing references) //IL_05be: Unknown result type (might be due to invalid IL or missing references) //IL_05c8: Expected O, but got Unknown //IL_05d3: Unknown result type (might be due to invalid IL or missing references) //IL_05dd: Expected O, but got Unknown //IL_05e7: Unknown result type (might be due to invalid IL or missing references) //IL_05f1: Expected O, but got Unknown //IL_0636: Unknown result type (might be due to invalid IL or missing references) //IL_0656: Unknown result type (might be due to invalid IL or missing references) //IL_0660: Expected O, but got Unknown //IL_0669: Unknown result type (might be due to invalid IL or missing references) //IL_0673: Expected O, but got Unknown if (!ready) { ready = true; Font val = FindFont(new string[2] { "norsebold", "norse" }); Font val2 = FindFont(new string[3] { "averiaseriflibre-regular", "averiaseriflibre", "averia" }); White = Solid(Color.white); Texture2D val3 = Gradient(PanelTop, PanelBottom, 128, Border); Texture2D background = Framed(Card, Hex("4A3A26")); Texture2D background2 = Framed(Hex("241B12"), Hex("4A3A26")); Texture2D background3 = Framed(Hex("241B12"), Hex("4A3A26")); Texture2D val4 = Framed(Hex("5A4222"), Gold); Texture2D background4 = Framed(Hex("33271A"), Hex("6B5230")); Texture2D val5 = Framed(Hex("443321"), Gold); Window = new GUIStyle(GUI.skin.window); GUIStyleState normal = Window.normal; GUIStyleState onNormal = Window.onNormal; GUIStyleState focused = Window.focused; Texture2D val6 = (Window.onFocused.background = val3); Texture2D val8 = (focused.background = val6); Texture2D background5 = (onNormal.background = val8); normal.background = background5; Window.border = new RectOffset(3, 3, 3, 3); Window.padding = new RectOffset(16, 16, 12, 12); Title = Label(val, 22, Gold, (FontStyle)0); Version = Label(val2, 13, Muted, (FontStyle)0); Version.alignment = (TextAnchor)6; Tab = new GUIStyle(GUI.skin.button); Tab.font = val ?? val2; Tab.fontSize = 15; Tab.normal.background = background3; Tab.hover.background = val5; Tab.active.background = val4; Tab.normal.textColor = Hex("D8CBB2"); Tab.hover.textColor = Gold; Tab.active.textColor = Gold; Tab.border = new RectOffset(3, 3, 3, 3); Tab.fixedHeight = 30f; Tab.richText = true; TabActive = new GUIStyle(Tab); GUIStyleState normal2 = TabActive.normal; Texture2D background6 = (TabActive.hover.background = val4); normal2.background = background6; GUIStyleState normal3 = TabActive.normal; Color textColor = (TabActive.hover.textColor = Gold); normal3.textColor = textColor; CardBox = new GUIStyle(GUI.skin.box); CardBox.normal.background = background; CardBox.border = new RectOffset(3, 3, 3, 3); CardBox.padding = new RectOffset(12, 12, 8, 10); CardBox.margin = new RectOffset(0, 0, 4, 6); CardTitle = Label(val ?? val2, 17, Gold, (FontStyle)0); Body = Label(val2, 14, Text, (FontStyle)0); Small = Label(val2, 13, Muted, (FontStyle)0); Mono = Label(val2, 13, Hex("E6DAC4"), (FontStyle)0); Hint = Label(val2, 13, Soft, (FontStyle)2); Section = Label(val ?? val2, 16, Gold, (FontStyle)0); Section.margin = new RectOffset(0, 0, 10, 2); Chip = new GUIStyle(GUI.skin.box); Chip.normal.background = White; Chip.font = val2; Chip.fontSize = 11; Chip.fontStyle = (FontStyle)1; Chip.normal.textColor = Hex("1A140E"); Chip.padding = new RectOffset(6, 6, 2, 2); Chip.margin = new RectOffset(0, 6, 3, 3); Chip.alignment = (TextAnchor)4; Chip.stretchWidth = false; TileBox = new GUIStyle(GUI.skin.box); TileBox.normal.background = background2; TileBox.border = new RectOffset(3, 3, 3, 3); TileBox.padding = new RectOffset(10, 10, 8, 8); TileBox.margin = new RectOffset(0, 8, 4, 4); TileValue = Label(val2, 24, Text, (FontStyle)1); TileLabel = Label(val2, 12, Muted, (FontStyle)0); Button = new GUIStyle(GUI.skin.button); Button.font = val2; Button.fontSize = 13; Button.normal.background = background4; GUIStyleState hover = Button.hover; Texture2D background7 = (Button.active.background = val5); hover.background = background7; Button.normal.textColor = Text; GUIStyleState hover2 = Button.hover; Color textColor2 = (Button.active.textColor = Gold); hover2.textColor = textColor2; Button.border = new RectOffset(3, 3, 3, 3); Button.padding = new RectOffset(10, 10, 5, 5); Banner = new GUIStyle(GUI.skin.box); Banner.normal.background = White; Banner.font = val2; Banner.fontSize = 14; Banner.fontStyle = (FontStyle)1; Banner.normal.textColor = Hex("1A140E"); Banner.alignment = (TextAnchor)3; Banner.padding = new RectOffset(12, 12, 8, 8); Banner.margin = new RectOffset(0, 0, 4, 8); } } private static GUIStyle Label(Font font, int size, Color color, FontStyle style) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown GUIStyle val = new GUIStyle(GUI.skin.label); if ((Object)(object)font != (Object)null) { val.font = font; } val.fontSize = size; val.fontStyle = style; val.normal.textColor = color; val.wordWrap = true; val.richText = true; val.margin = new RectOffset(0, 0, 1, 1); return val; } private static Font FindFont(string[] preferred) { List<Font> list = new List<Font>(); try { TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); foreach (TMP_FontAsset val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val.sourceFontFile != (Object)null) { list.Add(val.sourceFontFile); } } list.AddRange(Resources.FindObjectsOfTypeAll<Font>()); } catch (Exception) { } foreach (string value in preferred) { foreach (Font item in list) { if ((Object)(object)item != (Object)null && ((Object)item).name.Replace(" ", "").ToLower().Contains(value)) { return item; } } } return null; } public static string FontReport() { List<string> list = new List<string>(); try { TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); foreach (TMP_FontAsset val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val.sourceFontFile != (Object)null) { list.Add(((Object)val.sourceFontFile).name); } } Font[] array2 = Resources.FindObjectsOfTypeAll<Font>(); foreach (Font val2 in array2) { list.Add(((Object)val2).name); } } catch (Exception) { } return string.Join(", ", list.Distinct().ToArray()); } private static Texture2D Solid(Color c) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_000b: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, c); val.Apply(); ((Object)val).hideFlags = (HideFlags)61; return val; } private static Texture2D Gradient(Color top, Color bottom, int height, Color border) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(8, height); for (int i = 0; i < height; i++) { Color val2 = Color.Lerp(bottom, top, (float)i / (float)(height - 1)); for (int j = 0; j < 8; j++) { bool flag = j < 2 || j > 5 || i < 2 || i > height - 3; val.SetPixel(j, i, flag ? border : val2); } } val.Apply(); ((Object)val).hideFlags = (HideFlags)61; return val; } private static Texture2D Framed(Color fill, Color border) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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) Texture2D val = new Texture2D(8, 8); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { bool flag = (j == 0 || j == 7) && (i == 0 || i == 7); bool flag2 = j == 0 || j == 7 || i == 0 || i == 7; val.SetPixel(j, i, (Color)(flag ? new Color(border.r, border.g, border.b, 0.35f) : (flag2 ? border : fill))); } } val.Apply(); ((Object)val).hideFlags = (HideFlags)61; return val; } public static void ChipLabel(string text, Color color) { //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_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) Color backgroundColor = GUI.backgroundColor; GUI.backgroundColor = color; GUILayout.Label(text, Chip, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUI.backgroundColor = backgroundColor; } public static void BannerLabel(string text, Color color) { //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_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) Color backgroundColor = GUI.backgroundColor; GUI.backgroundColor = color; GUILayout.Label(text, Banner, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUI.backgroundColor = backgroundColor; } public static void Tile(string value, string label, Color valueColor, float width) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(TileBox, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(width) }); Color textColor = TileValue.normal.textColor; TileValue.normal.textColor = valueColor; GUILayout.Label(value, TileValue, (GUILayoutOption[])(object)new GUILayoutOption[0]); TileValue.normal.textColor = textColor; GUILayout.Label(label, TileLabel, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.EndVertical(); } public static void Bar(float fraction, Color color, float width, float height) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) Rect rect = GUILayoutUtility.GetRect(width, height, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(width), GUILayout.Height(height) }); ((Rect)(ref rect)).y = ((Rect)(ref rect)).y + 3f; Color color2 = GUI.color; GUI.color = new Color(1f, 1f, 1f, 0.08f); GUI.DrawTexture(rect, (Texture)(object)White); GUI.color = color; GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, Mathf.Max(2f, ((Rect)(ref rect)).width * Mathf.Clamp01(fraction)), ((Rect)(ref rect)).height), (Texture)(object)White); GUI.color = color2; } public static void BeginCard(Color strip) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) strips.Push(strip); GUILayout.BeginHorizontal(CardBox, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Space(12f); GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[0]); } public static void EndCard() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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) GUILayout.EndVertical(); Rect lastRect = GUILayoutUtility.GetLastRect(); Color color = ((strips.Count > 0) ? strips.Pop() : Gold); if ((int)Event.current.type == 7) { Color color2 = GUI.color; GUI.color = color; GUI.DrawTexture(new Rect(((Rect)(ref lastRect)).x - 10f, ((Rect)(ref lastRect)).y + 2f, 4f, ((Rect)(ref lastRect)).height - 4f), (Texture)(object)White); GUI.color = color2; } GUILayout.EndHorizontal(); } public static Color ForKind(string kind) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) switch (kind) { case "patch": case "incompatible": return Red; case "repeating": case "gamerepeating": return Orange; case "error": return Yellow; default: return Slate; } } public static Color Grade(double value, double good, double warn, bool higherIsBetter) { //IL_0031: 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) //IL_002b: 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_0011: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (higherIsBetter) { if (!(value >= good)) { if (!(value >= warn)) { return Red; } return Yellow; } return Green; } if (!(value <= good)) { if (!(value <= warn)) { return Red; } return Yellow; } return Green; } } public class AdminData { public class AdminPlayer { public string Name; public bool Online; public bool HasModList; public List<ModDifference> Diffs = new List<ModDifference>(); public List<string[]> Problems = new List<string[]>(); } public bool NotAdmin; public string Uptime = ""; public double Fps; public double FpsLow; public double MemoryMb; public int Objects; public int Online; public List<AdminPlayer> Players = new List<AdminPlayer>(); public AdminPlayer Get(string name) { AdminPlayer adminPlayer = Players.FirstOrDefault((AdminPlayer x) => x.Name == name); if (adminPlayer == null) { adminPlayer = new AdminPlayer(); adminPlayer.Name = name; Players.Add(adminPlayer); } return adminPlayer; } public string Serialize() { StringBuilder stringBuilder = new StringBuilder(); if (NotAdmin) { return "X\tnotadmin\n"; } stringBuilder.Append("H\t").Append(Uptime).Append('\t') .Append(Fps.ToString("0")) .Append('\t') .Append(FpsLow.ToString("0")) .Append('\t') .Append(MemoryMb.ToString("0")) .Append('\t') .Append(Objects) .Append('\t') .Append(Online) .Append('\n'); foreach (AdminPlayer player in Players) { stringBuilder.Append("P\t").Append(Clean(player.Name)).Append('\t') .Append(player.Online ? 1 : 0) .Append('\t') .Append(player.HasModList ? 1 : 0) .Append('\n'); foreach (ModDifference diff in player.Diffs) { stringBuilder.Append("D\t").Append(Clean(player.Name)).Append('\t') .Append(diff.Kind) .Append('\t') .Append(Clean(diff.Id)) .Append('\t') .Append(Clean(diff.PlayerVersion ?? "")) .Append('\t') .Append(Clean(diff.ServerVersion ?? "")) .Append('\n'); } foreach (string[] problem in player.Problems) { stringBuilder.Append("E\t").Append(Clean(player.Name)).Append('\t') .Append(string.Join("\t", problem.Select(Clean).ToArray())) .Append('\n'); } } return stringBuilder.ToString(); } public static AdminData Parse(string text) { AdminData adminData = new AdminData(); string[] array = text.Split('\n'); foreach (string text2 in array) { string[] array2 = text2.Split('\t'); if (array2.Length == 0) { continue; } try { switch (array2[0]) { case "X": adminData.NotAdmin = true; break; case "H": adminData.Uptime = array2[1]; adminData.Fps = double.Parse(array2[2]); adminData.FpsLow = double.Parse(array2[3]); adminData.MemoryMb = double.Parse(array2[4]); adminData.Objects = int.Parse(array2[5]); adminData.Online = int.Parse(array2[6]); break; case "P": { AdminPlayer adminPlayer = adminData.Get(array2[1]); adminPlayer.Online = array2[2] == "1"; adminPlayer.HasModList = array2[3] == "1"; break; } case "D": { ModDifference modDifference = new ModDifference(); modDifference.Kind = array2[2]; modDifference.Id = array2[3]; modDifference.PlayerVersion = ((array2[4].Length == 0) ? null : array2[4]); modDifference.ServerVersion = ((array2[5].Length == 0) ? null : array2[5]); adminData.Get(array2[1]).Diffs.Add(modDifference); break; } case "E": adminData.Get(array2[1]).Problems.Add(array2.Skip(2).ToArray()); break; } } catch (Exception) { } } return adminData; } private static string Clean(string s) { return (s ?? "").Replace('\t', ' ').Replace('\n', ' ').Replace('\r', ' '); } } public class TabContext { public string Lang; public List<Problem> Problems; public UpdateChecker Updates; public IEnumerable<ModRef> Packages; public bool Connected; public List<ModDifference> ServerDiff; public List<string> Duplicates; public List<KeyValuePair<string, double>> LoadTimes; public int PluginCount; public int InstalledCount; public Health Health; public List<KeyValuePair<string, int>> TopPrefabs; public bool InWorld; public int ObjectsLoaded; public int ObjectsKnown; public AdminData Admin; public HashSet<string> Expanded; } public static class Tabs { private static string T(string key, TabContext c) { return Text.T(key, c.Lang); } private static bool Toggle(TabContext c, string key, string label) { bool flag = c.Expanded.Contains(key); if (GUILayout.Button((flag ? "[-] " : "[+] ") + label, Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0])) { if (flag) { c.Expanded.Remove(key); } else { c.Expanded.Add(key); } flag = !flag; } return flag; } public static void Problems(TabContext c) { //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_06ef: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) List<Problem> list = c.Problems.Where((Problem p) => p.Kind != "engine").ToList(); List<Problem> list2 = c.Problems.Where((Problem p) => p.Kind == "engine").ToList(); List<IGrouping<string, Problem>> list3 = (from p in list group p by (p.Mod == null) ? ((p.PatchedBy.Count <= 0) ? "" : "?") : p.Mod.Name into g orderby (!(g.Key == "")) ? g.Sum((Problem p) => ((ReportWriter.Kind(p) == "patch" || ReportWriter.Kind(p) == "incompatible") ? 1000000 : 0) + Math.Min(p.Count, 999999)) : (-1) descending select g).ToList(); int num = list3.Count((IGrouping<string, Problem> g) => g.Key != "" && g.Key != "?"); List<KeyValuePair<ModRef, string>> list4 = ((c.Updates == null) ? new List<KeyValuePair<ModRef, string>>() : c.Updates.Updates(from m in c.Packages group m by m.FullPackage into g select g.First()).ToList()); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.Tile(num.ToString(), T("t_brokenmods", c), (num == 0) ? Theme.Green : Theme.Red, 150f); Theme.Tile(list.Sum((Problem p) => p.Count).ToString("N0"), T("t_errors", c), (list.Count == 0) ? Theme.Green : Theme.Orange, 150f); Theme.Tile(list4.Count.ToString(), T("t_updates", c), (list4.Count == 0) ? Theme.Muted : Theme.Blue, 150f); Theme.Tile(c.PluginCount.ToString(), T("t_plugins", c), Theme.Text, 150f); GUILayout.EndHorizontal(); if (list.Count == 0) { Theme.BannerLabel(T("noproblems", c), Theme.Green); } foreach (IGrouping<string, Problem> item in list3) { Problem problem = item.OrderBy((Problem p) => Rank(ReportWriter.Kind(p))).First(); Theme.BeginCard(Theme.ForKind(ReportWriter.Kind(problem))); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (item.Key == "") { GUILayout.Label(T("unknown", c), Theme.CardTitle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } else if (item.Key == "?") { GUILayout.Label(T("suspects", c), Theme.CardTitle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } else { GUILayout.Label(problem.Mod.Name, Theme.CardTitle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUILayout.Space(8f); GUILayout.Label(problem.Mod.PackageVersion ?? problem.Mod.Version, Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUILayout.FlexibleSpace(); if (c.Updates != null && c.Updates.HasUpdate(problem.Mod)) { Theme.ChipLabel(T("chip_update", c) + " " + c.Updates.Latest(problem.Mod), Theme.Green); } } GUILayout.EndHorizontal(); if (problem.Mod != null && problem.Mod.FullPackage != null) { GUILayout.Label(problem.Mod.FullPackage, Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } foreach (Problem item2 in from x in item orderby Rank(ReportWriter.Kind(x)), x.Count descending select x) { string text = ReportWriter.Kind(item2); GUILayout.Space(4f); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.ChipLabel(T("chip_" + text, c), Theme.ForKind(text)); string text2 = item2.Count.ToString("N0") + "×" + ((item2.PerSecond >= 5.0) ? (" · ~" + Math.Round(item2.PerSecond) + "/s") : ""); GUILayout.Label(text2, Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUILayout.EndHorizontal(); GUILayout.Label(item2.FirstLine, Theme.Mono, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (item2.Location != null) { GUILayout.Label(T("where", c) + " " + item2.Location, Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } if (item2.PatchedBy.Count > 0) { GUILayout.Label(T("patchedby", c) + " " + string.Join(", ", item2.PatchedBy.Select((ModRef m) => m.Display).ToArray()), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } if (item2.LikelyFromOtherFailure) { GUILayout.Label(T("likely", c), Theme.Hint, (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Label(T("hint_" + text, c), Theme.Hint, (GUILayoutOption[])(object)new GUILayoutOption[0]); } Theme.EndCard(); } HashSet<string> withProblems = new HashSet<string>(list3.Select((IGrouping<string, Problem> g) => g.Key)); List<KeyValuePair<ModRef, string>> list5 = list4.Where((KeyValuePair<ModRef, string> u) => !withProblems.Contains(u.Key.Name)).ToList(); if (list5.Count > 0) { GUILayout.Label(T("updates", c), Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0]); foreach (KeyValuePair<ModRef, string> item3 in list5) { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.ChipLabel(item3.Value, Theme.Blue); GUILayout.Label(item3.Key.Name + " <color=#D2C6B2>" + (item3.Key.PackageVersion ?? item3.Key.Version) + " -> " + item3.Value + "</color>", Theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.EndHorizontal(); } } if (list2.Count <= 0 || !Toggle(c, "engine", T("engine", c) + " (" + list2.Count + ")")) { return; } foreach (Problem item4 in list2.OrderByDescending((Problem x) => x.Count)) { GUILayout.Label("• " + item4.FirstLine + " <color=#D2C6B2>" + item4.Count + "×</color>", Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } } private static int Rank(string kind) { return kind switch { "patch" => 0, "incompatible" => 1, "repeating" => 2, "gamerepeating" => 3, "error" => 4, _ => 5, }; } public static void Mods(TabContext c) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_04c7: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) GUILayout.Label(T("tab_server_diff", c), Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (!c.Connected) { Theme.BannerLabel(T("notconnected", c), Theme.Slate); } else if (c.ServerDiff == null) { Theme.BannerLabel(T("noserverreply", c), Theme.Slate); } else { List<ModDifference> list = c.ServerDiff.Where((ModDifference d) => d.Kind != "extra").ToList(); if (list.Count == 0) { Theme.BannerLabel(T("diff_ok", c), Theme.Green); } else { Theme.BannerLabel(T((list.Count == 1) ? "diff_count1" : "diff_count", c).Replace("{n}", list.Count.ToString()), Theme.Orange); } foreach (ModDifference item in c.ServerDiff) { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (item.Kind == "missing") { Theme.ChipLabel(T("chip_missing", c), Theme.Red); } else if (item.Kind == "version") { Theme.ChipLabel(T("chip_version", c), Theme.Orange); } else { Theme.ChipLabel(T("chip_extra", c), Theme.Slate); } string text = ((item.Kind == "missing") ? (T("server", c) + " " + item.ServerVersion) : ((item.Kind == "version") ? (T("yours", c) + " " + item.PlayerVersion + " · " + T("server", c) + " " + item.ServerVersion) : item.PlayerVersion)); GUILayout.Label(item.Id + " <color=#D2C6B2>" + text + "</color>", Theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.EndHorizontal(); } if (c.ServerDiff.Any((ModDifference d) => d.Kind == "extra")) { GUILayout.Label(T("extra_hint", c), Theme.Hint, (GUILayoutOption[])(object)new GUILayoutOption[0]); } } if (c.Duplicates.Count > 0) { GUILayout.Label(T("duplicates", c), Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.BeginCard(Theme.Red); foreach (string duplicate in c.Duplicates) { GUILayout.Label(duplicate, Theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Label(T("duplicates_hint", c), Theme.Hint, (GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.EndCard(); } GUILayout.Label(T("loadtimes", c), Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (c.LoadTimes.Count == 0) { GUILayout.Label(T("loadtimes_none", c), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } else { double num = c.LoadTimes.Sum((KeyValuePair<string, double> t) => t.Value); GUILayout.Label(T("loadtimes_total", c).Replace("{n}", c.LoadTimes.Count.ToString()).Replace("{s}", num.ToString("0.0")), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); List<KeyValuePair<string, double>> list2 = c.LoadTimes.OrderByDescending((KeyValuePair<string, double> t) => t.Value).Take(15).ToList(); double num2 = Math.Max(0.1, list2[0].Value); foreach (KeyValuePair<string, double> item2 in list2) { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(item2.Key, Theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(250f) }); Theme.Bar((float)(item2.Value / num2), Theme.Grade(item2.Value, 2.0, 6.0, higherIsBetter: false), 300f, 12f); GUILayout.Label(item2.Value.ToString("0.0") + " s", Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }); GUILayout.EndHorizontal(); } int num3 = c.PluginCount - c.LoadTimes.Count; if (num3 > 0) { GUILayout.Label(T("loadtimes_before", c).Replace("{n}", num3.ToString()), Theme.Hint, (GUILayoutOption[])(object)new GUILayoutOption[0]); } } GUILayout.Space(6f); GUILayout.Label(T("installed", c).Replace("{n}", c.InstalledCount.ToString()), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } public static void Performance(TabContext c) { //IL_0091: 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_010f: 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_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) Health health = c.Health; GUILayout.Label(T("perf_game", c), Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (health.SampleCount < 30) { Theme.BannerLabel(T("measuring", c), Theme.Slate); } else { double value = health.AverageFps(); double value2 = health.LowFps(); double value3 = health.WorstFrameMs(); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.Tile(value.ToString("0"), T("t_fps", c), Theme.Grade(value, 50.0, 30.0, higherIsBetter: true), 150f); Theme.Tile(value2.ToString("0"), T("t_fpslow", c), Theme.Grade(value2, 40.0, 20.0, higherIsBetter: true), 150f); Theme.Tile(value3.ToString("0") + " ms", T("t_worst", c), Theme.Grade(value3, 50.0, 120.0, higherIsBetter: false), 150f); GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.Tile(Health.Mb(GC.GetTotalMemory(forceFullCollection: false)), T("t_memmods", c), Theme.Text, 150f); Theme.Tile(Health.Mb(Profiler.GetTotalAllocatedMemoryLong()), T("t_memunity", c), Theme.Text, 150f); Theme.Tile(health.GcPerMinute()[0].ToString("0.0"), T("t_gc", c), Theme.Text, 150f); GUILayout.EndHorizontal(); GUILayout.Label(T("gc_hint", c), Theme.Hint, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(T("objects", c), Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (!c.InWorld) { GUILayout.Label(T("notinworld", c), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } else { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.Tile(c.ObjectsLoaded.ToString("N0"), T("t_loaded", c), Theme.Grade(c.ObjectsLoaded, 6000.0, 12000.0, higherIsBetter: false), 140f); Theme.Tile(c.ObjectsKnown.ToString("N0"), T("t_known", c), Theme.Text, 140f); GUILayout.EndHorizontal(); if (c.TopPrefabs.Count > 0) { double num = c.TopPrefabs[0].Value; foreach (KeyValuePair<string, int> topPrefab in c.TopPrefabs) { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(topPrefab.Key, Theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(250f) }); Theme.Bar((float)((double)topPrefab.Value / num), Theme.Gold, 300f, 12f); GUILayout.Label(topPrefab.Value.ToString("N0"), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }); GUILayout.EndHorizontal(); } } GUILayout.Label(T("objects_hint", c), Theme.Hint, (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Label("Mod Doctor", Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.Tile(health.OwnMsPerFrame().ToString("0.000") + " ms", T("t_own", c), Theme.Grade(health.OwnMsPerFrame(), 0.05, 0.3, higherIsBetter: false), 140f); Theme.Tile((health.OwnMsTotal() / 1000.0).ToString("0.0") + " s", T("t_owntotal", c), Theme.Text, 140f); Theme.Tile(health.ErrorsSeen.ToString("N0"), T("t_ownerrors", c), Theme.Text, 140f); GUILayout.EndHorizontal(); } public static void Server(TabContext c) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_05bd: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_05c8: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) AdminData admin = c.Admin; if (admin == null) { Theme.BannerLabel(T("loading", c), Theme.Slate); return; } if (admin.NotAdmin) { Theme.BannerLabel(T("notadmin", c), Theme.Red); return; } GUILayout.Label(T("srv_health", c), Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.Tile(admin.Uptime, T("uptime", c), Theme.Text, 120f); Theme.Tile(admin.Fps.ToString("0"), T("t_fps", c), Theme.Grade(admin.Fps, 25.0, 15.0, higherIsBetter: true), 120f); Theme.Tile(admin.FpsLow.ToString("0"), T("t_fpslow", c), Theme.Grade(admin.FpsLow, 20.0, 10.0, higherIsBetter: true), 120f); Theme.Tile(admin.MemoryMb.ToString("0") + " MB", T("t_memmods", c), Theme.Text, 120f); Theme.Tile(admin.Online.ToString(), T("t_online", c), Theme.Text, 120f); GUILayout.EndHorizontal(); GUILayout.Label(T("objects_known", c) + " " + admin.Objects.ToString("N0"), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(T("srv_players", c), Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0]); List<AdminData.AdminPlayer> list = (from p in admin.Players where p.Name != "(server)" orderby p.Online descending, p.Name select p).ToList(); if (list.Count == 0) { GUILayout.Label(T("noplayers", c), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } foreach (AdminData.AdminPlayer item in list) { List<ModDifference> list2 = item.Diffs.Where((ModDifference d) => d.Kind != "extra").ToList(); Theme.BeginCard((list2.Count > 0 || item.Problems.Any((string[] e) => e.Length > 2 && (e[2] == "patch" || e[2] == "incompatible" || e[2] == "repeating"))) ? Theme.Orange : Theme.Green); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(item.Name, Theme.CardTitle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUILayout.Space(10f); Theme.ChipLabel(item.Online ? T("online", c) : T("offline", c), item.Online ? Theme.Green : Theme.Slate); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (!item.HasModList) { GUILayout.Label(T("nomoddoctor", c), Theme.Hint, (GUILayoutOption[])(object)new GUILayoutOption[0]); } else if (list2.Count == 0) { GUILayout.Label(T("diff_ok", c), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } foreach (ModDifference item2 in list2) { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.ChipLabel((item2.Kind == "missing") ? T("chip_missing", c) : T("chip_version", c), (item2.Kind == "missing") ? Theme.Red : Theme.Orange); GUILayout.Label(item2.Id + " <color=#D2C6B2>" + ((item2.Kind == "missing") ? (T("server", c) + " " + item2.ServerVersion) : (item2.PlayerVersion + " · " + T("server", c) + " " + item2.ServerVersion)) + "</color>", Theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.EndHorizontal(); } foreach (string[] item3 in item.Problems.Take(6)) { ProblemLine(c, item3); } if (item.HasModList && item.Problems.Count == 0) { GUILayout.Label(T("noproblems", c), Theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } Theme.EndCard(); } AdminData.AdminPlayer adminPlayer = admin.Players.FirstOrDefault((AdminData.AdminPlayer p) => p.Name == "(server)"); GUILayout.Label(T("srv_own", c), Theme.Section, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (adminPlayer == null || adminPlayer.Problems.Count == 0) { Theme.BannerLabel(T("noproblems", c), Theme.Green); return; } Theme.BeginCard(Theme.Orange); foreach (string[] item4 in adminPlayer.Problems.Take(8)) { ProblemLine(c, item4); } Theme.EndCard(); } private static void ProblemLine(TabContext c, string[] e) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (e.Length >= 5) { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); Theme.ChipLabel(T("chip_" + e[2], c), Theme.ForKind(e[2])); GUILayout.Label(((e[0].Length > 0) ? (e[0] + " " + e[1]) : T("gamecode", c)) + " <color=#D2C6B2>" + e[3] + "×</color>", Theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.EndHorizontal(); GUILayout.Label(e[4], Theme.Mono, (GUILayoutOption[])(object)new GUILayoutOption[0]); } } } public class ModRef { public string Guid; public string Name; public string Version; public string Folder; public string PackageNamespace; public string PackageName; public string PackageVersion; public string FullPackage { get { if (PackageNamespace != null) { return PackageNamespace + "-" + PackageName; } return null; } } public string Display => Name + " " + (PackageVersion ?? Version); } public class Problem { public string Key; public string Kind; public string ExceptionType; public string FirstLine; public string Location; public ModRef Mod; public List<ModRef> PatchedBy = new List<ModRef>(); public string LogSource; public int Count; public DateTime First; public DateTime Last; public string RawStack; public bool Resolved; public bool LikelyFromOtherFailure; public double PerSecond { get { double totalSeconds = (Last - First).TotalSeconds; if (!(totalSeconds < 1.0)) { return (double)Count / totalSeconds; } return 0.0; } } } public class Diagnosis { private readonly object sync = new object(); private readonly Dictionary<string, Problem> problems = new Dictionary<string, Problem>(); private readonly Queue<Problem> pending = new Queue<Problem>(); private readonly Dictionary<Assembly, ModRef> assemblyOwner = new Dictionary<Assembly, ModRef>(); private readonly Dictionary<string, ModRef> typeOwner = new Dictionary<string, ModRef>(); private readonly Dictionary<string, ModRef> byGuid = new Dictionary<string, ModRef>(); private readonly Dictionary<string, ModRef> byLogName = new Dictionary<string, ModRef>(); private readonly Dictionary<string, ModRef> harmonyOwner = new Dictionary<string, ModRef>(); private bool indexed; private int version; public int PluginCount; private static readonly Regex DmdFrame = new Regex("DMD<([^:>]+)::([^>]+)>"); private static readonly Regex ManagedFrame = new Regex("^\\s*(?:at\\s+)?(?:\\(wrapper [^)]*\\)\\s*)?([A-Za-z_<][\\w\\.\\+/<>`\\[\\],]*)\\s*\\("); private static readonly string[] IncompatibleMarkers = new string[9] { "MissingMethodException", "MissingFieldException", "TypeLoadException", "BadImageFormatException", "MissingMemberException", "EntryPointNotFoundException", "Undefined target method", "Could not find method", "expected reference type" }; private static readonly Regex Numbers = new Regex("\\d+"); public int Version { get { lock (sync) { return version; } } } public void Record(string condition, string stackTrace, string logSource) { if (string.IsNullOrEmpty(condition) || condition.StartsWith("[Mod Doctor]")) { return; } string text = FirstLine(condition); string text2 = (string.IsNullOrEmpty(stackTrace) ? ExtractInlineStack(condition) : stackTrace); string key = Normalize(text) + "|" + TopFrames(text2, 3) + "|" + logSource; lock (sync) { if (problems.TryGetValue(key, out var value)) { value.Count++; value.Last = DateTime.Now; if (value.Count == 100 || value.Count == 1000) { version++; } return; } value = new Problem(); value.Key = key; value.FirstLine = ((text.Length > 300) ? text.Substring(0, 300) : text); value.ExceptionType = ExceptionType(text); value.RawStack = text2; value.LogSource = logSource; value.Count = 1; value.First = (value.Last = DateTime.Now); problems[key] = value; pending.Enqueue(value); version++; } } public void ResolvePending() { if (!indexed) { return; } while (true) { Problem problem; lock (sync) { if (pending.Count == 0) { break; } problem = pending.Dequeue(); } try { Resolve(problem); } catch (Exception ex) { ModDoctorPlugin.Log.LogDebug((object)("Could not attribute an error: " + ex.Message)); } lock (sync) { problem.Resolved = true; version++; } } } public List<Problem> Snapshot() { lock (sync) { return problems.Values.Where((Problem p) => p.Resolved).ToList(); } } public IEnumerable<ModRef> Packages() { return byGuid.Values.Where((ModRef m) => m.PackageNamespace != null); } public void IndexPlugins() { string fullPath = Path.GetFullPath(Paths.PluginPath); Dictionary<string, ModRef> dictionary = new Dictionary<string, ModRef>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { PluginInfo value = pluginInfo.Value; ModRef modRef = new ModRef(); modRef.Guid = value.Metadata.GUID; modRef.Name = value.Metadata.Name; modRef.Version = value.Metadata.Version.ToString(); modRef.Folder = TopFolder(fullPath, value.Location); ReadPackage(fullPath, modRef); byGuid[modRef.Guid] = modRef; byLogName[modRef.Name] = modRef; harmonyOwner[modRef.Guid] = modRef; if (modRef.Folder != null && !dictionary.ContainsKey(modRef.Folder)) { dictionary[modRef.Folder] = modRef; } if ((Object)(object)value.Instance != (Object)null) { assemblyOwner[((object)value.Instance).GetType().Assembly] = modRef; } } PluginCount = byGuid.Count; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (!assemblyOwner.ContainsKey(assembly) && !assembly.IsDynamic) { string location; try { location = assembly.Location; } catch (Exception) { continue; } string text = TopFolder(fullPath, location); if (text != null && dictionary.TryGetValue(text, out var value2)) { assemblyOwner[assembly] = value2; } } } foreach (KeyValuePair<Assembly, ModRef> item in assemblyOwner) { Type[] types; try { types = item.Key.GetTypes(); } catch (ReflectionTypeLoadException ex2) { types = ex2.Types; } catch (Exception) { continue; } Type[] array = types; foreach (Type type in array) { if (!(type == null) && type.FullName != null) { typeOwner[type.FullName.Replace('/', '+')] = item.Value; } } } indexed = true; } private static string TopFolder(string pluginRoot, string location) { if (string.IsNullOrEmpty(location)) { return null; } string fullPath = Path.GetFullPath(location); if (!fullPath.StartsWith(pluginRoot, StringComparison.OrdinalIgnoreCase)) { return null; } string text = fullPath.Substring(pluginRoot.Length).TrimStart('\\', '/'); int num = text.IndexOfAny(new char[2] { '\\', '/' }); if (num >= 0) { return text.Substring(0, num); } return null; } private static void ReadPackage(string pluginRoot, ModRef mod) { if (mod.Folder == null) { return; } int num = mod.Folder.IndexOf('-'); if (num <= 0 || num == mod.Folder.Length - 1) { return; } mod.PackageNamespace = mod.Folder.Substring(0, num); mod.PackageName = mod.Folder.Substring(num + 1); string path = Path.Combine(Path.Combine(pluginRoot, mod.Folder), "manifest.json"); if (File.Exists(path)) { Match match = Regex.Match(File.ReadAllText(path), "\"version_number\"\\s*:\\s*\"([^\"]+)\""); if (match.Success) { mod.PackageVersion = match.Groups[1].Value; } } } private void Resolve(Problem p) { if (p.LogSource != null && byLogName.TryGetValue(p.LogSource, out var value)) { p.Mod = value; } string[] array = (p.RawStack ?? "").Split('\n'); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length == 0) { continue; } Match match = DmdFrame.Match(text2); if (match.Success) { string text3 = match.Groups[1].Value.Replace('/', '+'); string value2 = match.Groups[2].Value; if (p.Location == null) { p.Location = text3 + "." + value2; } if (typeOwner.TryGetValue(text3, out var value3)) { if (p.Mod == null) { p.Mod = value3; } break; } foreach (ModRef item in PatchersOf(text3, value2)) { if (!p.PatchedBy.Contains(item)) { p.PatchedBy.Add(item); } } if (p.PatchedBy.Count > 0) { break; } continue; } Match match2 = ManagedFrame.Match(text2); if (!match2.Success) { continue; } string text4 = match2.Groups[1].Value.Replace('/', '+'); int num = text4.LastIndexOf('.'); if (num <= 0) { continue; } string text5 = text4.Substring(0, num); if (p.Location == null && !IsFramework(text5)) { p.Location = text4; } if (typeOwner.TryGetValue(text5, out var value4)) { if (p.Mod == null) { p.Mod = value4; } p.Location = text4; break; } } p.Kind = Classify(p); if (p.Mod == null && p.PatchedBy.Count == 1) { p.Mod = p.PatchedBy[0]; } if (p.Mod != null || p.PatchedBy.Count <= 1) { return; } List<ModRef> list; lock (sync) { list = p.PatchedBy.Where((ModRef m) => problems.Values.Any((Problem o) => o != p && o.Resolved && o.Mod == m && (o.Kind == "patch" || o.Kind == "incompatible"))).ToList(); } if (list.Count == 1) { p.Mod = list[0]; p.LikelyFromOtherFailure = true; } } private IEnumerable<ModRef> PatchersOf(string typeName, string methodName) { List<ModRef> list = new List<ModRef>(); Type type = AccessTools.TypeByName(typeName); if (type == null) { return list; } IEnumerable<MethodBase> enumerable = ((methodName == ".ctor") ? type.GetConstructors(AccessTools.all).Cast<MethodBase>() : (from m in type.GetMethods(AccessTools.all) where m.Name == methodName select m).Cast<MethodBase>()); foreach (MethodBase item in enumerable) { Patches patchInfo = Harmony.GetPatchInfo(item); if (patchInfo == null) { continue; } IEnumerable<Patch> enumerable2 = patchInfo.Prefixes.Concat(patchInfo.Postfixes).Concat(patchInfo.Transpilers).Concat(patchInfo.Finalizers); foreach (Patch item2 in enumerable2) { ModRef value = null; MethodInfo patchMethod = item2.PatchMethod; if (patchMethod != null && patchMethod.DeclaringType != null) { assemblyOwner.TryGetValue(patchMethod.DeclaringType.Assembly, out value); } if (value == n