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 DudeWhatAreMyStats v0.9.0
BepInEx/plugins/DudeWhatAreMyStats.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("DudeWhatAreMyStats")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.9.0.0")] [assembly: AssemblyInformationalVersion("0.9.0+d11884351d02605e4b17f2bf4b79f12ad4e2cca1")] [assembly: AssemblyProduct("DudeWhatAreMyStats")] [assembly: AssemblyTitle("DudeWhatAreMyStats")] [assembly: AssemblyVersion("0.9.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DudeWhatAreMyStats { internal static class Commands { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; public static ConsoleEvent <>9__0_1; public static ConsoleEvent <>9__0_2; public static ConsoleEvent <>9__0_3; internal void <Register>b__0_0(ConsoleEventArgs args) { if ((Object)(object)Player.m_localPlayer == (Object)null) { Terminal context = args.Context; if (context != null) { context.AddString("No character loaded."); } } else { StatsPanel.Toggle(); } } internal void <Register>b__0_1(ConsoleEventArgs args) { PlayerListHud.Toggle(); Terminal context = args.Context; if (context != null) { context.AddString("Player list " + (DwamsConfig.ShowPlayerList.Value ? "on." : "off.")); } } internal void <Register>b__0_2(ConsoleEventArgs args) { StatsNetwork.RequestNow(); Terminal context = args.Context; if (context != null) { context.AddString("Asked everyone online, and the server, for stats."); } } internal void <Register>b__0_3(ConsoleEventArgs args) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(string.Format("panel: {0} | holding pause: {1} | answered live: {2}", StatsPanel.IsOpen ? "open" : "closed", StatsPause.Holding, StatsNetwork.KnownCount + 1)); stringBuilder.AppendLine(StatsNetwork.ServerHasStore ? $"server store: answering, {StatsNetwork.StoredCount} character(s) remembered" : "server store: no answer yet (the server may not run this mod, which only costs you offline players)"); if (StatsStore.IsServer) { stringBuilder.AppendLine(StatsStore.Loaded ? $"this game is the server: {StatsStore.Count} character(s) in {StatsStore.Path}" : "this game is the server, but the store is off or has no world yet"); } foreach (Snapshot item in StatsNetwork.Roster()) { string lastSeenText = item.LastSeenText; string text = (item.IsLocal ? "you" : (item.Online ? "online" : ((lastSeenText.Length > 0) ? ("last seen " + lastSeenText) : "offline"))); stringBuilder.AppendLine(item.Name + " (" + text + "): " + StatGroups.Count(item.Kills) + " kills, " + StatGroups.Count(item.Deaths) + " deaths, " + StatGroups.Count(item.Bosses) + " bosses, " + StatGroups.Duration(item.Played) + " played, best " + item.BestSkillText); } Terminal context = args.Context; if (context != null) { context.AddString(stringBuilder.ToString().TrimEnd(Array.Empty<char>())); } } } internal static void Register() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { if ((Object)(object)Player.m_localPlayer == (Object)null) { Terminal context = args.Context; if (context != null) { context.AddString("No character loaded."); } } else { StatsPanel.Toggle(); } }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("dwams", "Dude What Are My Stats: open or close the stats panel", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj2 = <>c.<>9__0_1; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { PlayerListHud.Toggle(); Terminal context = args.Context; if (context != null) { context.AddString("Player list " + (DwamsConfig.ShowPlayerList.Value ? "on." : "off.")); } }; <>c.<>9__0_1 = val2; obj2 = (object)val2; } new ConsoleCommand("dwams_hud", "Dude What Are My Stats: show or hide the always-on player list", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj3 = <>c.<>9__0_2; if (obj3 == null) { ConsoleEvent val3 = delegate(ConsoleEventArgs args) { StatsNetwork.RequestNow(); Terminal context = args.Context; if (context != null) { context.AddString("Asked everyone online, and the server, for stats."); } }; <>c.<>9__0_2 = val3; obj3 = (object)val3; } new ConsoleCommand("dwams_refresh", "Dude What Are My Stats: ask the other players for their stats again", (ConsoleEvent)obj3, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj4 = <>c.<>9__0_3; if (obj4 == null) { ConsoleEvent val4 = delegate(ConsoleEventArgs args) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(string.Format("panel: {0} | holding pause: {1} | answered live: {2}", StatsPanel.IsOpen ? "open" : "closed", StatsPause.Holding, StatsNetwork.KnownCount + 1)); stringBuilder.AppendLine(StatsNetwork.ServerHasStore ? $"server store: answering, {StatsNetwork.StoredCount} character(s) remembered" : "server store: no answer yet (the server may not run this mod, which only costs you offline players)"); if (StatsStore.IsServer) { stringBuilder.AppendLine(StatsStore.Loaded ? $"this game is the server: {StatsStore.Count} character(s) in {StatsStore.Path}" : "this game is the server, but the store is off or has no world yet"); } foreach (Snapshot item in StatsNetwork.Roster()) { string lastSeenText = item.LastSeenText; string text = (item.IsLocal ? "you" : (item.Online ? "online" : ((lastSeenText.Length > 0) ? ("last seen " + lastSeenText) : "offline"))); stringBuilder.AppendLine(item.Name + " (" + text + "): " + StatGroups.Count(item.Kills) + " kills, " + StatGroups.Count(item.Deaths) + " deaths, " + StatGroups.Count(item.Bosses) + " bosses, " + StatGroups.Duration(item.Played) + " played, best " + item.BestSkillText); } Terminal context = args.Context; if (context != null) { context.AddString(stringBuilder.ToString().TrimEnd(Array.Empty<char>())); } }; <>c.<>9__0_3 = val4; obj4 = (object)val4; } new ConsoleCommand("dwams_status", "Dude What Are My Stats: what the scoreboard currently knows", (ConsoleEvent)obj4, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } [BepInPlugin("DeathMonger.DudeWhatAreMyStats", "Dude What Are My Stats", "0.9.0")] public class DudeWhatAreMyStatsMod : BaseUnityPlugin { public const string ModGuid = "DeathMonger.DudeWhatAreMyStats"; public const string ModName = "Dude What Are My Stats"; public const string ModVersion = "0.9.0"; internal static ConfigEntry<bool> ModEnabled; private readonly Harmony _harmony = new Harmony("DeathMonger.DudeWhatAreMyStats"); internal static DudeWhatAreMyStatsMod Instance { get; private set; } internal static ManualLogSource Log { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Mod Enabled", true, "Master toggle for the entire mod. Set to false to disable every patch, the stats panel and the console command without removing the DLL. Requires a game restart to take effect."); if (!ModEnabled.Value) { Log.LogInfo((object)"[DudeWhatAreMyStats] Mod Enabled = false in config; skipping patches and commands."); return; } DwamsConfig.Bind(this); Commands.Register(); _harmony.PatchAll(); Log.LogInfo((object)"[DudeWhatAreMyStats] 0.9.0 loaded."); } private void Update() { if (ModEnabled.Value) { UiKit.ObserveFocus(); StatsNetwork.Update(); StatsStore.Update(); if ((Object)(object)Player.m_localPlayer == (Object)null) { StatsPanel.Close(); PlayerListHud.Hide(); } else { StatsPanel.Update(); PlayerListHud.Update(); } } } private void OnDestroy() { StatsPause.Release(); _harmony.UnpatchSelf(); } internal ConfigEntry<T> BindLocal<T>(string section, string key, T defaultValue, string description) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>())); } internal ConfigEntry<float> BindLocalRange(string section, string key, float defaultValue, float min, float max, string description) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<float>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>())); } internal ConfigEntry<int> BindLocalRangeInt(string section, string key, int defaultValue, int min, int max, string description) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<int>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(min, max), Array.Empty<object>())); } internal static void Message(string text) { if (!((Object)(object)MessageHud.instance == (Object)null)) { MessageHud.instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true); } } } internal static class DwamsConfig { internal static ConfigEntry<KeyboardShortcut> OpenKey; internal static ConfigEntry<bool> PauseWhileOpen; internal static ConfigEntry<bool> AskOtherPlayers; internal static ConfigEntry<float> RefreshSeconds; internal static ConfigEntry<bool> RememberOfflinePlayers; internal static ConfigEntry<float> PushMinutes; internal static ConfigEntry<bool> ServerStoreEnabled; internal static ConfigEntry<float> ServerKeepDays; internal static ConfigEntry<int> ServerMaxCharacters; internal static ConfigEntry<bool> ShowZeroStats; internal static ConfigEntry<string> SortColumn; internal static ConfigEntry<bool> SortDescending; internal static ConfigEntry<string> CollapsedGroups; internal static ConfigEntry<string> PanelSize; internal static ConfigEntry<string> PanelPosition; internal static ConfigEntry<int> ListScrollRows; internal static ConfigEntry<int> TopCreatureCount; internal static ConfigEntry<bool> ShowPlayerList; internal static ConfigEntry<KeyboardShortcut> PlayerListKey; internal static ConfigEntry<bool> PlayerListIncludeOffline; internal static ConfigEntry<float> PlayerListRefreshSeconds; internal static ConfigEntry<int> PlayerListMaxRows; internal static ConfigEntry<HudCorner> PlayerListCorner; internal static ConfigEntry<string> PlayerListOffset; internal static ConfigEntry<float> PlayerListFontSize; internal static ConfigEntry<bool> FixTreasureDiscoveryCount; internal static void Bind(DudeWhatAreMyStatsMod mod) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) OpenKey = mod.BindLocal<KeyboardShortcut>("Keys", "Open Stats", new KeyboardShortcut((KeyCode)105, Array.Empty<KeyCode>()), "Opens and closes the stats panel. Escape closes it too."); PauseWhileOpen = mod.BindLocal("Behaviour", "Pause While Open", defaultValue: true, "Pause the game while the stats panel is open, the way the ESC menu does. This goes through the game's own pause, so it only takes effect when the game would let the ESC menu pause it: alone in a solo or hosted game. On a server with other players online nothing freezes, unless Pause My Server is installed and grants the pause."); AskOtherPlayers = mod.BindLocal("Behaviour", "Ask Other Players", defaultValue: true, "Ask everyone else online for their stats so the scoreboard can compare you. Each player's own game answers for them, so only players who also run this mod appear. Turning this off works both ways: you stop asking, you stop answering, and the server is told to forget the record it already holds, so you leave everyone else's scoreboard as well as emptying your own."); RefreshSeconds = mod.BindLocalRange("Behaviour", "Refresh Seconds", 10f, 0f, 120f, "How often to ask the other players again while the panel is open. 0 asks only when the panel opens and when you press Refresh."); RememberOfflinePlayers = mod.BindLocal("Behaviour", "Show Offline Players", defaultValue: true, "List players who are not online, as well as those who are. That covers anyone who logs out while you are still playing, and, if the server also runs this mod, everyone it remembers from before you logged in, each marked with how long ago they were last seen. Without the mod on the server there is nowhere to remember anyone, so only the first case applies. Turn off to list only players online now."); PushMinutes = mod.BindLocalRange("Behaviour", "Push Minutes", 5f, 0f, 60f, "How often to hand your own stats to the server, so it can show them to others once you have logged off. It also happens when you open the panel and when you leave the world. 0 stops sending them at all, which keeps you off the board for anyone who was not online at the same time as you. A server without this mod ignores them either way."); ServerStoreEnabled = mod.BindLocal("Server", "Server Store Enabled", defaultValue: true, "Server-side setting, ignored on a client. Keep a record of each character's last known stats so the scoreboard can show players who are not online. The file lives in BepInEx/config/DudeWhatAreMyStats/, one per world. Turn off to keep nothing, which leaves every client showing only the players online."); ServerKeepDays = mod.BindLocalRange("Server", "Server Keep Days", 30f, 0f, 365f, "Server-side setting, ignored on a client. Forget a character the server has not heard from in this many days, so a world does not accumulate one-time visitors forever. 0 keeps every character for good."); ServerMaxCharacters = mod.BindLocalRangeInt("Server", "Server Max Characters", 100, 10, 200, "Server-side setting, ignored on a client. The most characters to remember; past this the least recently seen are dropped. The whole set travels to a client in one message, and an oversized one would jam that player's connection rather than merely fail, so this is a real ceiling and not just housekeeping. 100 is far more than a group of friends will ever need."); ShowZeroStats = mod.BindLocal("Display", "Show Zero Stats", defaultValue: false, "Show stats that are still zero in the Details tab. Off hides them, which is most of the 200-odd stats the game tracks."); SortColumn = mod.BindLocal("Display", "Sort Column", "Kills", "Which scoreboard column is sorted, remembered between sessions. Click a column header to change it rather than editing this."); SortDescending = mod.BindLocal("Display", "Sort Descending", defaultValue: true, "Whether the sorted scoreboard column runs highest first. Click a column header twice to flip it."); CollapsedGroups = mod.BindLocal("Display", "Collapsed Groups", "", "Which sections are folded away in the Details tab, kept between sessions. Click a section header, or Expand all / Collapse all, in the panel itself rather than editing this."); PanelSize = mod.BindLocal("Display", "Panel Size", "820,620", "Width and height of the stats panel, remembered when you drag its bottom-right corner."); PanelPosition = mod.BindLocal("Display", "Panel Position", "0,0", "Where the stats panel sits, as an offset from the screen center, remembered when you drag it by its title. Set to 0,0 to put it back in the middle."); ListScrollRows = mod.BindLocalRangeInt("Display", "List Scroll Rows", 4, 1, 20, "How many rows a list moves per notch of the mouse wheel."); TopCreatureCount = mod.BindLocalRangeInt("Display", "Top Creature Count", 15, 0, 100, "How many creatures to list in the Details tab's Creatures killed section, most killed first. 0 hides it."); ShowPlayerList = mod.BindLocal("Player List", "Show Player List", defaultValue: false, "Keep a small list of players and how many times each has died on screen all the time, most deaths first. It stays up over the map and the inventory, and steps aside only when the game hides its own HUD (Ctrl+F3), during cutscenes, behind the pause menu and the death or teleport fade, and while the stats panel is open. Off by default. The console command dwams_hud turns it on and off too."); PlayerListKey = mod.BindLocal<KeyboardShortcut>("Player List", "Toggle Key", new KeyboardShortcut((KeyCode)0, Array.Empty<KeyCode>()), "A key that turns the player list on and off. Unbound by default, since almost every letter is taken by the game or another mod; pick one that is free in your own setup. It stands down while you are typing in any text box."); PlayerListIncludeOffline = mod.BindLocal("Player List", "Include Offline Players", defaultValue: false, "Also list players who are not online, from the server's record of them. Off keeps the list to the people actually playing, which is what an always-visible list is usually for. Needs the mod on the server to have anyone to show."); PlayerListRefreshSeconds = mod.BindLocalRange("Player List", "Refresh Seconds", 30f, 5f, 300f, "How often the list asks the other players for their numbers while the stats panel is closed. Deaths change rarely, so this can be slow. Your own count is always current."); PlayerListMaxRows = mod.BindLocalRangeInt("Player List", "Max Rows", 10, 1, 30, "The most players to list. Any beyond that are summed up as \"+N more\"."); PlayerListCorner = mod.BindLocal("Player List", "Corner", HudCorner.TopLeft, "Which corner of the screen the list sits in."); PlayerListOffset = mod.BindLocal("Player List", "Offset", "16,300", "How far in from that corner, as x,y in pixels at 1080p. Both numbers are measured inward from the corner, whichever corner it is. The default sits on the left, below the hotbar; move it if it overlaps something else on your screen."); PlayerListFontSize = mod.BindLocalRange("Player List", "Font Size", 16f, 10f, 30f, "Text size of the player list."); FixTreasureDiscoveryCount = mod.BindLocal("Fixes", "Fix Treasure Discovery Count", defaultValue: true, "Correct a bug in Valheim itself that counts a treasure chest as newly found every time it is opened. The game marks a chest discovered over a message it never registered a handler for, so the mark is never written and the treasure numbers on the stats panel read high. This registers the missing handler on chests that keep a discovery stat, which also stops the repeated \"Failed to find rpc method 327122920\" warnings in the log. It works while your own game owns the chest, which in a dungeon it usually does; a chest held by a player without the mod still miscounts for them. Turn off to leave the game exactly as it ships."); } } internal static class LocalStats { private const int RawStats = 0; private static bool _warnedLayout; private static bool _warnedSkills; private static bool _warnedRead; internal static Snapshot Read() { try { return ReadInner(); } catch (Exception arg) { if (!_warnedRead) { _warnedRead = true; DudeWhatAreMyStatsMod.Log.LogError((object)$"[DudeWhatAreMyStats] Could not read the local character's stats: {arg}"); } return null; } } private static Snapshot ReadInner() { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) Game instance = Game.instance; PlayerProfile val = (((Object)(object)instance != (Object)null) ? instance.GetPlayerProfile() : null); if (val == null) { return null; } Snapshot snapshot = new Snapshot { Name = (string.IsNullOrEmpty(val.GetName()) ? "Viking" : val.GetName()), ProfileId = val.GetPlayerID(), PeerId = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.GetUID() : 0), IsLocal = true, Online = true, ReceivedAt = Time.unscaledTime }; PlayerStats val2 = Raw(val); if (val2 != null) { if (val2.m_stats != null) { foreach (KeyValuePair<PlayerStatType, float> stat in val2.m_stats) { if (stat.Value != 0f) { snapshot.Stats[stat.Key] = stat.Value; } } } if (val2.m_enemyStats != null && val2.m_enemyStats.Length != 0 && val2.m_enemyStats[0] != null) { foreach (KeyValuePair<string, float> item in val2.m_enemyStats[0]) { if (item.Value > 0f) { snapshot.Creatures.Add(item); } } snapshot.Creatures.Sort((KeyValuePair<string, float> a, KeyValuePair<string, float> b) => b.Value.CompareTo(a.Value)); int num = ((DwamsConfig.TopCreatureCount != null) ? DwamsConfig.TopCreatureCount.Value : 15); if (num >= 0 && snapshot.Creatures.Count > num) { snapshot.Creatures.RemoveRange(num, snapshot.Creatures.Count - num); } } } ReadSkills(snapshot); return snapshot; } private static void ReadSkills(Snapshot snap) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) try { Player localPlayer = Player.m_localPlayer; Skills val = (((Object)(object)localPlayer != (Object)null) ? ((Character)localPlayer).GetSkills() : null); if ((Object)(object)val == (Object)null) { return; } foreach (Skill skill in val.GetSkillList()) { if (skill != null && skill.m_info != null && !(skill.m_level <= 0f)) { snap.Skills.Add(new KeyValuePair<SkillType, float>(skill.m_info.m_skill, skill.m_level)); } } snap.Skills.Sort((KeyValuePair<SkillType, float> a, KeyValuePair<SkillType, float> b) => b.Value.CompareTo(a.Value)); } catch (Exception ex) { if (!_warnedSkills) { _warnedSkills = true; DudeWhatAreMyStatsMod.Log.LogError((object)("[DudeWhatAreMyStats] Could not read this character's skills; the rest of the stats still work. " + ex.Message)); } } } private static PlayerStats Raw(PlayerProfile profile) { try { PlayerStats[] playerStats = profile.m_playerStats; if (playerStats != null && playerStats.Length != 0 && playerStats[0] != null) { return playerStats[0]; } } catch (Exception ex) { if (!_warnedLayout) { _warnedLayout = true; DudeWhatAreMyStatsMod.Log.LogError((object)("[DudeWhatAreMyStats] The player profile's stats are not laid out the way this build expects, so the panel will be empty. This usually means a Valheim update moved them. Details: " + ex.Message)); } return null; } if (!_warnedLayout) { _warnedLayout = true; DudeWhatAreMyStatsMod.Log.LogWarning((object)"[DudeWhatAreMyStats] The player profile has no raw stats slot; the panel will be empty."); } return null; } } [HarmonyPatch(typeof(Game), "Start")] internal static class Game_Start_Patch { [HarmonyPostfix] private static void Postfix() { StatsNetwork.Reset(); StatsNetwork.Register(); StatsStore.Load(); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] internal static class ZNet_Shutdown_Patch { [HarmonyPrefix] private static void Prefix() { StatsPanel.Close(); StatsNetwork.PushLocal(force: true); StatsStore.Unload(); StatsNetwork.Reset(); } } [HarmonyPatch(typeof(TextInput), "IsVisible")] internal static class TextInput_IsVisible_Patch { [HarmonyPostfix] private static void Postfix(ref bool __result) { if (!__result && (StatsPanel.IsOpen || StatsPanel.JustClosed)) { __result = true; } } } [HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")] internal static class ZInput_GetMouseScrollWheel_Patch { [HarmonyPostfix] private static void Postfix(ref float __result) { if (__result != 0f && StatsPanel.IsOpen) { __result = 0f; } } } [HarmonyPatch(typeof(Container), "Awake")] internal static class Container_Awake_Patch { private const string SentName = "discovered"; [HarmonyPostfix] private static void Postfix(Container __instance) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 if (!DwamsConfig.FixTreasureDiscoveryCount.Value || (int)__instance.m_discoverStat == 206) { return; } ZNetView nview = (((Object)(object)__instance.m_rootObjectOverride != (Object)null) ? ((Component)__instance.m_rootObjectOverride).GetComponent<ZNetView>() : ((Component)__instance).GetComponent<ZNetView>()); if ((Object)(object)nview == (Object)null || nview.GetZDO() == null) { return; } nview.Unregister("discovered"); nview.Register<int>("discovered", (Action<long, int>)delegate(long sender, int keyHash) { ZDO zDO = nview.GetZDO(); if (zDO != null) { zDO.Set(keyHash, true); } }); } } internal enum HudCorner { TopLeft, TopRight, BottomLeft, BottomRight } internal static class PlayerListHud { private const float BaseFont = 16f; private const float BaseWidth = 230f; private const float BaseCountColumn = 56f; private const float BasePad = 8f; private const float LineEm = 1.25f; private const int MaxNameChars = 16; private static readonly string LineHeight = "<line-height=" + 1.25f.ToString(CultureInfo.InvariantCulture) + "em>"; private const string Placeholder = "<alpha=#00>0</alpha>"; private static GameObject _root; private static RectTransform _box; private static TextMeshProUGUI _names; private static TextMeshProUGUI _counts; private static float _nextRedraw; private static float _nextRequest; private static string _layoutKey; private static float _scale = 1f; internal static void Update() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (DwamsConfig.PlayerListKey != null && Keys.IsDown(DwamsConfig.PlayerListKey.Value) && Keys.CanTakeInput()) { Toggle(); } if (!Wanted()) { if ((Object)(object)_root != (Object)null) { _root.SetActive(false); } } else if (!((Object)(object)_root == (Object)null) || Create()) { if (!_root.activeSelf) { _root.SetActive(true); _nextRedraw = 0f; } KeepFresh(); if (!(Time.unscaledTime < _nextRedraw)) { _nextRedraw = Time.unscaledTime + 1f; Redraw(); } } } internal static void Toggle() { if (DwamsConfig.ShowPlayerList != null) { DwamsConfig.ShowPlayerList.Value = !DwamsConfig.ShowPlayerList.Value; DudeWhatAreMyStatsMod.Message(DwamsConfig.ShowPlayerList.Value ? "Player list on" : "Player list off"); _nextRedraw = 0f; _nextRequest = 0f; } } internal static void Hide() { if ((Object)(object)_root != (Object)null) { _root.SetActive(false); } } private static bool Wanted() { if (DwamsConfig.ShowPlayerList == null || !DwamsConfig.ShowPlayerList.Value) { return false; } Player localPlayer = Player.m_localPlayer; Hud instance = Hud.instance; if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance == (Object)null) { return false; } if (instance.m_userHidden || ((Character)localPlayer).InCutscene()) { return false; } if (Menu.IsVisible() || StatsPanel.IsOpen || LoadingScreenShowing(instance)) { return false; } return true; } private static bool LoadingScreenShowing(Hud hud) { CanvasGroup loadingScreen = hud.m_loadingScreen; if ((Object)(object)loadingScreen != (Object)null && ((Component)loadingScreen).gameObject.activeInHierarchy) { return loadingScreen.alpha > 0.01f; } return false; } private static void KeepFresh() { float num = Mathf.Max(5f, (DwamsConfig.PlayerListRefreshSeconds != null) ? DwamsConfig.PlayerListRefreshSeconds.Value : 30f); if (StatsPanel.IsOpen) { _nextRequest = Time.unscaledTime + num; } else if (!(Time.unscaledTime < _nextRequest)) { _nextRequest = Time.unscaledTime + num; StatsNetwork.Request(DwamsConfig.PlayerListIncludeOffline != null && DwamsConfig.PlayerListIncludeOffline.Value); } } private static void Redraw() { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) ApplyLayout(); bool flag = DwamsConfig.PlayerListIncludeOffline != null && DwamsConfig.PlayerListIncludeOffline.Value; int num = ((DwamsConfig.PlayerListMaxRows != null) ? DwamsConfig.PlayerListMaxRows.Value : 10); List<Snapshot> list = new List<Snapshot>(); foreach (Snapshot item in StatsNetwork.Roster()) { if (item.IsLocal || item.Online || flag) { list.Add(item); } } list.Sort(delegate(Snapshot a, Snapshot b) { int num7 = b.Deaths.CompareTo(a.Deaths); return (num7 == 0) ? string.Compare(a.Name ?? "", b.Name ?? "", StringComparison.OrdinalIgnoreCase) : num7; }); StringBuilder stringBuilder = new StringBuilder(LineHeight).Append(Colored("Deaths", UiKit.Header)); StringBuilder stringBuilder2 = new StringBuilder(LineHeight).Append("<alpha=#00>0</alpha>"); int num2 = 0; foreach (Snapshot item2 in list) { if (num2 >= num) { break; } num2++; Color color = (item2.IsLocal ? UiKit.Gold : (item2.Online ? UiKit.Body : UiKit.Dim)); stringBuilder.Append('\n').Append(Colored(Clean(item2.Name), color)); stringBuilder2.Append('\n').Append(Colored(StatGroups.Count(item2.Deaths), color)); } int num3 = list.Count - num2; if (num3 > 0) { stringBuilder.Append('\n').Append(Colored("+" + num3 + " more", UiKit.Dim)); stringBuilder2.Append('\n').Append("<alpha=#00>0</alpha>"); } ((TMP_Text)_names).text = stringBuilder.ToString(); ((TMP_Text)_counts).text = stringBuilder2.ToString(); int num4 = 1 + num2 + ((num3 > 0) ? 1 : 0); float num5 = FontSize(); float num6 = 8f * _scale; _box.sizeDelta = new Vector2(230f * _scale, (float)num4 * num5 * 1.25f + num6 * 2f); } private static string Clean(string name) { if (string.IsNullOrEmpty(name)) { return "Viking"; } StringBuilder stringBuilder = new StringBuilder(name.Length); foreach (char c in name) { if (c != '<' && c != '\\' && !char.IsControl(c) && c != '\u2028' && c != '\u2029') { stringBuilder.Append(c); } } string text = stringBuilder.ToString().Trim(); if (text.Length == 0) { return "Viking"; } if (text.Length > 16) { return text.Substring(0, 13) + "..."; } return text; } private static string Colored(string text, Color color) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) return "<color=#" + ColorUtility.ToHtmlStringRGB(color) + ">" + text + "</color>"; } private static float FontSize() { if (DwamsConfig.PlayerListFontSize == null) { return 16f; } return DwamsConfig.PlayerListFontSize.Value; } private static bool Create() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0067: 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) if ((Object)(object)MessageHud.instance == (Object)null && (Object)(object)TextInput.instance == (Object)null) { return false; } UiKit.EnsureFont(); _root = new GameObject("DWAMS_PlayerList"); Canvas obj = _root.AddComponent<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 899; CanvasScaler obj2 = _root.AddComponent<CanvasScaler>(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); obj2.matchWidthOrHeight = 0.5f; Image obj3 = UiKit.Panel(_root.transform, "Box", new Color(0f, 0f, 0f, 0.38f)); ((Graphic)obj3).raycastTarget = false; _box = ((Graphic)obj3).rectTransform; _names = MakeLabel("Names", (TextAlignmentOptions)257); _counts = MakeLabel("Counts", (TextAlignmentOptions)260); _layoutKey = null; _nextRedraw = 0f; _nextRequest = 0f; ApplyLayout(); return true; } private static TextMeshProUGUI MakeLabel(string name, TextAlignmentOptions align) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI obj = UiKit.Text((Transform)(object)_box, name, "", FontSize(), align, UiKit.Body); ((TMP_Text)obj).overflowMode = (TextOverflowModes)0; ((TMP_Text)obj).richText = true; ((TMP_Text)obj).parseCtrlCharacters = false; RectTransform rectTransform = ((TMP_Text)obj).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; return obj; } private static void ApplyLayout() { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_box == (Object)null) { return; } HudCorner hudCorner = ((DwamsConfig.PlayerListCorner != null) ? DwamsConfig.PlayerListCorner.Value : HudCorner.TopLeft); string text = ((DwamsConfig.PlayerListOffset != null) ? DwamsConfig.PlayerListOffset.Value : "16,300"); float num = FontSize(); string text2 = hudCorner.ToString() + "|" + text + "|" + num.ToString(CultureInfo.InvariantCulture); if (!(text2 == _layoutKey)) { _layoutKey = text2; _scale = num / 16f; float num2 = 8f * _scale; float num3 = 56f * _scale; if ((Object)(object)_names != (Object)null) { ((TMP_Text)_names).fontSize = num; ((TMP_Text)_names).rectTransform.offsetMin = new Vector2(num2, num2); ((TMP_Text)_names).rectTransform.offsetMax = new Vector2(0f - (num2 + num3), 0f - num2); } if ((Object)(object)_counts != (Object)null) { ((TMP_Text)_counts).fontSize = num; ((TMP_Text)_counts).rectTransform.offsetMin = new Vector2(num2, num2); ((TMP_Text)_counts).rectTransform.offsetMax = new Vector2(0f - num2, 0f - num2); } Vector2 val = default(Vector2); switch (hudCorner) { case HudCorner.TopRight: ((Vector2)(ref val))..ctor(1f, 1f); break; case HudCorner.BottomLeft: ((Vector2)(ref val))..ctor(0f, 0f); break; case HudCorner.BottomRight: ((Vector2)(ref val))..ctor(1f, 0f); break; default: ((Vector2)(ref val))..ctor(0f, 1f); break; } _box.anchorMin = val; _box.anchorMax = val; _box.pivot = val; TryPair(text, out var a, out var b); float num4 = ((val.x > 0.5f) ? (-1f) : 1f); float num5 = ((val.y > 0.5f) ? (-1f) : 1f); _box.anchoredPosition = new Vector2(num4 * Mathf.Abs(a), num5 * Mathf.Abs(b)); } } private static void TryPair(string text, out float a, out float b) { a = 16f; b = 300f; if (string.IsNullOrEmpty(text)) { return; } string[] array = text.Split(new char[1] { ',' }); if (array.Length == 2) { NumberStyles style = NumberStyles.Float; CultureInfo invariantCulture = CultureInfo.InvariantCulture; if (float.TryParse(array[0].Trim(), style, invariantCulture, out var result)) { a = result; } if (float.TryParse(array[1].Trim(), style, invariantCulture, out var result2)) { b = result2; } } } } internal sealed class Snapshot { internal const int Schema = 2; internal string Name = ""; internal long ProfileId; internal long PeerId; internal bool IsLocal; internal bool Online = true; internal float ReceivedAt; internal long LastSeenUtc; internal bool FromStore; internal readonly Dictionary<PlayerStatType, float> Stats = new Dictionary<PlayerStatType, float>(); internal readonly List<KeyValuePair<SkillType, float>> Skills = new List<KeyValuePair<SkillType, float>>(); internal readonly List<KeyValuePair<string, float>> Creatures = new List<KeyValuePair<string, float>>(); internal long Identity { get { if (ProfileId == 0L) { return PeerId; } return ProfileId; } } internal float Kills => Stat((PlayerStatType)6); internal float Deaths => Stat((PlayerStatType)0); internal float Bosses => Stat((PlayerStatType)85); internal float Played => Stat((PlayerStatType)21) + Stat((PlayerStatType)22); internal float KillDeath { get { if (!(Deaths >= 1f)) { return Kills; } return Kills / Deaths; } } internal KeyValuePair<SkillType, float> BestSkill { get { KeyValuePair<SkillType, float> result = new KeyValuePair<SkillType, float>((SkillType)0, 0f); foreach (KeyValuePair<SkillType, float> skill in Skills) { if (skill.Value > result.Value) { result = skill; } } return result; } } internal float BestSkillLevel => BestSkill.Value; internal string LastSeenText { get { if (Online || LastSeenUtc <= 0) { return ""; } long num = NowUtc() - LastSeenUtc; if (num < 0) { return "just now"; } if (num < 90) { return "just now"; } if (num < 3600) { return num / 60 + "m ago"; } if (num < 86400) { return num / 3600 + "h ago"; } return num / 86400 + "d ago"; } } internal string BestSkillText { get { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) KeyValuePair<SkillType, float> bestSkill = BestSkill; if ((int)bestSkill.Key == 0 || bestSkill.Value <= 0f) { return "-"; } return SkillName(bestSkill.Key) + " " + Mathf.FloorToInt(bestSkill.Value); } } internal float SkillTotal { get { float num = 0f; foreach (KeyValuePair<SkillType, float> skill in Skills) { num += skill.Value; } return num; } } internal float Stat(PlayerStatType stat) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (!Stats.TryGetValue(stat, out var value)) { return 0f; } return value; } internal static long NowUtc() { return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds; } internal unsafe static string SkillName(SkillType skill) { string text = "$skill_" + ((object)(*(SkillType*)(&skill))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(); string text2 = ((Localization.instance != null) ? Localization.instance.Localize(text) : text); if (!string.IsNullOrEmpty(text2) && text2 != text && !text2.StartsWith("[", StringComparison.Ordinal)) { return text2; } return Spaced(((object)(*(SkillType*)(&skill))/*cast due to .constrained prefix*/).ToString()); } private static string Spaced(string name) { StringBuilder stringBuilder = new StringBuilder(name.Length + 4); for (int i = 0; i < name.Length; i++) { if (i > 0 && char.IsUpper(name[i]) && !char.IsUpper(name[i - 1])) { stringBuilder.Append(' '); } stringBuilder.Append(name[i]); } return stringBuilder.ToString(); } internal ZPackage Pack() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected I4, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected I4, but got Unknown ZPackage val = new ZPackage(); val.Write(2); val.Write(Name ?? ""); val.Write(ProfileId); val.Write(LastSeenUtc); val.Write(Stats.Count); foreach (KeyValuePair<PlayerStatType, float> stat in Stats) { val.Write((int)stat.Key); val.Write(stat.Value); } val.Write(Skills.Count); foreach (KeyValuePair<SkillType, float> skill in Skills) { val.Write((int)skill.Key); val.Write(skill.Value); } val.Write(Creatures.Count); foreach (KeyValuePair<string, float> creature in Creatures) { val.Write(creature.Key ?? ""); val.Write(creature.Value); } return val; } internal static Snapshot Unpack(ZPackage pkg) { //IL_005a: 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_0090: 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) if (pkg == null) { return null; } try { pkg.SetPos(0); if (pkg.ReadInt() != 2) { return null; } Snapshot snapshot = new Snapshot { Name = pkg.ReadString(), ProfileId = pkg.ReadLong(), LastSeenUtc = pkg.ReadLong() }; int num = pkg.ReadInt(); for (int i = 0; i < num; i++) { PlayerStatType key = (PlayerStatType)pkg.ReadInt(); float value = pkg.ReadSingle(); snapshot.Stats[key] = value; } int num2 = pkg.ReadInt(); for (int j = 0; j < num2; j++) { SkillType key2 = (SkillType)pkg.ReadInt(); float value2 = pkg.ReadSingle(); snapshot.Skills.Add(new KeyValuePair<SkillType, float>(key2, value2)); } int num3 = pkg.ReadInt(); for (int k = 0; k < num3; k++) { string key3 = pkg.ReadString(); float value3 = pkg.ReadSingle(); snapshot.Creatures.Add(new KeyValuePair<string, float>(key3, value3)); } return snapshot; } catch (Exception ex) { DudeWhatAreMyStatsMod.Log.LogWarning((object)("[DudeWhatAreMyStats] Could not read a stats snapshot: " + ex.Message)); return null; } } } internal static class StatGroups { private enum Unit { Count, Seconds, Meters } internal static readonly string[] Order = new string[9] { "Combat", "Deaths", "Exploration", "Building", "Crafting", "Gathering", "Creatures", "Forsaken powers", "Other" }; private static readonly HashSet<string> TimeStats = new HashSet<string>(StringComparer.Ordinal) { "TimeInBase", "TimeOutOfBase" }; private static readonly HashSet<string> MeterStats = new HashSet<string>(StringComparer.Ordinal) { "DistanceTraveled", "DistanceWalk", "DistanceRun", "DistanceSail", "DistanceAir", "DistanceSailHelm", "ExploreNorth", "ExploreSouth", "ExploreEast", "ExploreWest", "ExploreNorthNoMap", "ExploreSouthNoMap", "ExploreEastNoMap", "ExploreWestNoMap", "MaxBuildingHeight", "MaxBuildingHeightWorld", "DeepestDungeon" }; private static readonly HashSet<string> Combat = new HashSet<string>(StringComparer.Ordinal) { "EnemyHits", "EnemyKills", "EnemyKillsLastHits", "PlayerHits", "PlayerKills", "HitsTakenEnemies", "HitsTakenPlayers", "ArrowsShot", "SkeletonSummons", "BossKills", "BossLastHits", "BossKillMultiplayer", "BossKillSolo" }; private static readonly HashSet<string> Exploration = new HashSet<string>(StringComparer.Ordinal) { "PortalsUsed", "PortalDungeonIn", "PortalDungeonOut", "LeviathanSink", "LavaLeviathanSink", "DeepestDungeon", "TimeInBase", "TimeOutOfBase", "Sleep", "WorldLoads", "PlayerSpawn", "ConsecutiveDaysSurvived", "ConsecutiveDaysSurvivedMax" }; private static readonly HashSet<string> Building = new HashSet<string>(StringComparer.Ordinal) { "Builds", "PlaceStacks", "BuildPiecesRemoved", "MaxBuildingHeight", "MaxBuildingHeightWorld", "MaxComfort", "VillagePointsMax" }; private static readonly HashSet<string> Gathering = new HashSet<string>(StringComparer.Ordinal) { "TreeChops", "Tree", "LogChops", "Logs", "MineHits", "Mines", "BeesHarvested", "SapHarvested", "ItemsPickedUp", "FishHooked", "FishLost", "FishCaught", "TreeFir", "TreeOak", "TreePine", "TreeAshlands", "TreeYggdrasilShoot", "TreeSwamp", "TreeBeech", "TreeBirch", "TreeSnowFir", "TreeSnowPine" }; private static readonly HashSet<string> Creatures = new HashSet<string>(StringComparer.Ordinal) { "CreatureTamed", "TamedPetting", "TamedCommand", "RavenHits", "RavenTalk", "RavenAppear" }; private static readonly Dictionary<PlayerStatType, string> SectionCache = new Dictionary<PlayerStatType, string>(); private static readonly Dictionary<PlayerStatType, string> LabelCache = new Dictionary<PlayerStatType, string>(); internal unsafe static string Section(PlayerStatType stat) { //IL_0005: 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) if (SectionCache.TryGetValue(stat, out var value)) { return value; } string text = Classify(((object)(*(PlayerStatType*)(&stat))/*cast due to .constrained prefix*/).ToString()); SectionCache[stat] = text; return text; } private static string Classify(string n) { if (n == "Deaths" || n.StartsWith("DeathBy", StringComparison.Ordinal)) { return "Deaths"; } if (Combat.Contains(n)) { return "Combat"; } if (n.StartsWith("SetPower", StringComparison.Ordinal) || n.StartsWith("UsePower", StringComparison.Ordinal) || n == "SetGuardianPower" || n == "UseGuardianPower") { return "Forsaken powers"; } if (Building.Contains(n) || n.StartsWith("BuiltPieces", StringComparison.Ordinal) || n.StartsWith("BuildCluster", StringComparison.Ordinal)) { return "Building"; } switch (n) { default: if (!n.StartsWith("Craft", StringComparison.Ordinal)) { if (Gathering.Contains(n) || n.StartsWith("TreeTier", StringComparison.Ordinal) || n.StartsWith("MineTier", StringComparison.Ordinal) || n.StartsWith("Harvest", StringComparison.Ordinal) || n.StartsWith("FishCaughtTier", StringComparison.Ordinal)) { return "Gathering"; } if (Exploration.Contains(n) || n.StartsWith("Distance", StringComparison.Ordinal) || n.StartsWith("Explore", StringComparison.Ordinal) || n.StartsWith("Treasure", StringComparison.Ordinal)) { return "Exploration"; } if (Creatures.Contains(n)) { return "Creatures"; } return "Other"; } goto case "CraftsOrUpgrades"; case "CraftsOrUpgrades": case "Crafts": case "Upgrades": return "Crafting"; } } internal unsafe static string Label(PlayerStatType stat) { //IL_0005: 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) if (LabelCache.TryGetValue(stat, out var value)) { return value; } string text = Spaced(((object)(*(PlayerStatType*)(&stat))/*cast due to .constrained prefix*/).ToString()); LabelCache[stat] = text; return text; } private static string Spaced(string name) { StringBuilder stringBuilder = new StringBuilder(name.Length + 8); for (int i = 0; i < name.Length; i++) { char c = name[i]; if (i > 0 && char.IsUpper(c) && !char.IsUpper(name[i - 1])) { stringBuilder.Append(' '); } else if (i > 0 && char.IsDigit(c) && !char.IsDigit(name[i - 1])) { stringBuilder.Append(' '); } stringBuilder.Append(c); } return stringBuilder.ToString(); } internal unsafe static string Format(PlayerStatType stat, float value) { string item = ((object)(*(PlayerStatType*)(&stat))/*cast due to .constrained prefix*/).ToString(); if (TimeStats.Contains(item)) { return Duration(value); } if (MeterStats.Contains(item)) { return Distance(value); } return Count(value); } internal static string Count(float value) { if (Math.Abs(value - (float)Math.Round(value)) < 0.05f) { return ((long)Math.Round(value)).ToString("N0"); } return value.ToString("N1"); } internal static string Duration(float seconds) { if (seconds <= 0f) { return "0s"; } TimeSpan timeSpan = TimeSpan.FromSeconds(seconds); if (timeSpan.TotalDays >= 1.0) { return $"{(int)timeSpan.TotalDays}d {timeSpan.Hours}h"; } if (timeSpan.TotalHours >= 1.0) { return $"{(int)timeSpan.TotalHours}h {timeSpan.Minutes}m"; } if (timeSpan.TotalMinutes >= 1.0) { return $"{(int)timeSpan.TotalMinutes}m {timeSpan.Seconds}s"; } return $"{(int)timeSpan.TotalSeconds}s"; } internal static string Distance(float meters) { if (Math.Abs(meters) >= 1000f) { return (meters / 1000f).ToString("N1") + " km"; } return Math.Round(meters).ToString("N0") + " m"; } } internal static class StatsNetwork { private const string RpcRequest = "DWAMS_Request"; private const string RpcResponse = "DWAMS_Response"; private const string RpcPush = "DWAMS_Push"; private const string RpcAskAll = "DWAMS_AskAll"; private const string RpcAll = "DWAMS_All"; private const string RpcForget = "DWAMS_Forget"; private const int AllSchema = 1; private const float SettleSeconds = 3f; private const float ServerAskSeconds = 60f; private const float ServeCooldown = 10f; private static readonly Dictionary<long, Snapshot> _remote = new Dictionary<long, Snapshot>(); private static readonly Dictionary<long, Snapshot> _stored = new Dictionary<long, Snapshot>(); private static ZRoutedRpc _registeredOn; private static float _lastRequestAt = -999f; private static float _prevRequestAt = -999f; private static float _nextAutoRequestAt; private static float _nextPushAt; private static float _nextServerAskAt; private static bool _serverAnswered; private static bool _forgetSent; private static readonly Dictionary<long, float> _servedAt = new Dictionary<long, float>(); private static readonly HashSet<string> _connected = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static int KnownCount => _remote.Count; internal static int StoredCount => _stored.Count; internal static bool ServerHasStore => _serverAnswered; internal static void Register() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance == null || instance == _registeredOn) { return; } _registeredOn = instance; try { instance.Register<ZPackage>("DWAMS_Request", (Action<long, ZPackage>)RPC_Request); instance.Register<ZPackage>("DWAMS_Response", (Action<long, ZPackage>)RPC_Response); instance.Register<ZPackage>("DWAMS_Push", (Action<long, ZPackage>)RPC_Push); instance.Register<ZPackage>("DWAMS_AskAll", (Action<long, ZPackage>)RPC_AskAll); instance.Register<ZPackage>("DWAMS_All", (Action<long, ZPackage>)RPC_All); instance.Register<ZPackage>("DWAMS_Forget", (Action<long, ZPackage>)RPC_Forget); DudeWhatAreMyStatsMod.Log.LogInfo((object)"[DudeWhatAreMyStats] Stats RPCs registered."); } catch (Exception arg) { DudeWhatAreMyStatsMod.Log.LogError((object)$"[DudeWhatAreMyStats] Could not register the stats RPCs: {arg}"); } } internal static void Reset() { _remote.Clear(); _stored.Clear(); _lastRequestAt = -999f; _prevRequestAt = -999f; _nextAutoRequestAt = 0f; _nextPushAt = 0f; _nextServerAskAt = 0f; _serverAnswered = false; _forgetSent = false; _servedAt.Clear(); } internal static void Update() { Register(); PushTick(); if (StatsPanel.IsOpen) { float num = ((DwamsConfig.RefreshSeconds != null) ? DwamsConfig.RefreshSeconds.Value : 10f); if (!(num <= 0f) && !(Time.unscaledTime < _nextAutoRequestAt)) { _nextAutoRequestAt = Time.unscaledTime + num; Request(); } } } internal static void Request(bool includeServer = true) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown if (DwamsConfig.AskOtherPlayers != null && !DwamsConfig.AskOtherPlayers.Value) { return; } ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && !((Object)(object)ZNet.instance == (Object)null)) { _prevRequestAt = _lastRequestAt; _lastRequestAt = Time.unscaledTime; _nextAutoRequestAt = Time.unscaledTime + Mathf.Max(1f, (DwamsConfig.RefreshSeconds != null) ? DwamsConfig.RefreshSeconds.Value : 10f); instance.InvokeRoutedRPC(0L, "DWAMS_Request", new object[1] { (object)new ZPackage() }); if (includeServer) { AskServer(); } } } internal static void RequestNow() { _nextServerAskAt = 0f; Request(); } private static void RPC_Request(long sender, ZPackage pkg) { try { if ((DwamsConfig.AskOtherPlayers != null && !DwamsConfig.AskOtherPlayers.Value) || (Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsDedicated() || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)Game.instance == (Object)null || sender == ZNet.GetUID()) { return; } Snapshot snapshot = LocalStats.Read(); if (snapshot != null) { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(sender, "DWAMS_Response", new object[1] { snapshot.Pack() }); } } } catch (Exception ex) { DudeWhatAreMyStatsMod.Log.LogWarning((object)("[DudeWhatAreMyStats] Could not answer a stats request: " + ex.Message)); } } private static void RPC_Response(long sender, ZPackage pkg) { Snapshot snapshot = Snapshot.Unpack(pkg); if (snapshot != null) { snapshot.PeerId = sender; snapshot.IsLocal = false; snapshot.FromStore = false; snapshot.ReceivedAt = Time.unscaledTime; _remote[snapshot.Identity] = snapshot; StatsPanel.OnRosterChanged(snapshot.Identity); } } private static void PushTick() { if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } if (DwamsConfig.AskOtherPlayers != null && !DwamsConfig.AskOtherPlayers.Value) { if (!_forgetSent) { SendForget(); } } else { _forgetSent = false; PushLocal(); } } internal static void PushLocal(bool force = false) { try { if (DwamsConfig.AskOtherPlayers != null && !DwamsConfig.AskOtherPlayers.Value) { return; } float num = ((DwamsConfig.PushMinutes != null) ? DwamsConfig.PushMinutes.Value : 5f); if (num <= 0f || (!force && Time.unscaledTime < _nextPushAt)) { return; } ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && !((Object)(object)ZNet.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)Game.instance == (Object)null)) { Snapshot snapshot = LocalStats.Read(); if (snapshot != null) { _nextPushAt = Time.unscaledTime + Mathf.Max(30f, num * 60f); instance.InvokeRoutedRPC("DWAMS_Push", new object[1] { snapshot.Pack() }); } } } catch (Exception ex) { DudeWhatAreMyStatsMod.Log.LogWarning((object)("[DudeWhatAreMyStats] Could not send our stats to the server: " + ex.Message)); } } private static void SendForget() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown try { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && !((Object)(object)ZNet.instance == (Object)null) && !((Object)(object)Game.instance == (Object)null)) { PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); long num = ((playerProfile != null) ? playerProfile.GetPlayerID() : 0); if (num != 0L) { _forgetSent = true; ZPackage val = new ZPackage(); val.Write(num); instance.InvokeRoutedRPC("DWAMS_Forget", new object[1] { val }); } } } catch (Exception ex) { DudeWhatAreMyStatsMod.Log.LogWarning((object)("[DudeWhatAreMyStats] Could not ask the server to forget us: " + ex.Message)); } } private static void RPC_Forget(long sender, ZPackage pkg) { try { if (StatsStore.IsServer && StatsStore.Loaded && pkg != null) { pkg.SetPos(0); long num = pkg.ReadLong(); if (num != 0L && StatsStore.Forget(num)) { DudeWhatAreMyStatsMod.Log.LogInfo((object)"[DudeWhatAreMyStats] Dropped a character's stored stats at their own request."); } } } catch (Exception ex) { DudeWhatAreMyStatsMod.Log.LogWarning((object)("[DudeWhatAreMyStats] Could not handle a forget request: " + ex.Message)); } } private static void RPC_Push(long sender, ZPackage pkg) { try { if (StatsStore.IsServer && StatsStore.Loaded) { Snapshot snapshot = Snapshot.Unpack(pkg); if (snapshot != null) { snapshot.PeerId = sender; snapshot.IsLocal = false; StatsStore.Put(snapshot); } } } catch (Exception ex) { DudeWhatAreMyStatsMod.Log.LogWarning((object)("[DudeWhatAreMyStats] Could not record a pushed snapshot: " + ex.Message)); } } internal static void AskServer() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown if (DwamsConfig.RememberOfflinePlayers == null || DwamsConfig.RememberOfflinePlayers.Value) { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && !((Object)(object)ZNet.instance == (Object)null) && !(Time.unscaledTime < _nextServerAskAt)) { _nextServerAskAt = Time.unscaledTime + 60f; instance.InvokeRoutedRPC("DWAMS_AskAll", new object[1] { (object)new ZPackage() }); } } } private static void RPC_AskAll(long sender, ZPackage pkg) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown try { if (!StatsStore.IsServer || !StatsStore.Loaded) { return; } float unscaledTime = Time.unscaledTime; if (_servedAt.TryGetValue(sender, out var value) && unscaledTime - value < 10f) { return; } _servedAt[sender] = unscaledTime; List<Snapshot> list = StatsStore.All(); ZPackage val = new ZPackage(); val.Write(1); val.Write(list.Count); foreach (Snapshot item in list) { val.Write(item.Pack().GetArray()); } ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(sender, "DWAMS_All", new object[1] { val }); } } catch (Exception ex) { DudeWhatAreMyStatsMod.Log.LogWarning((object)("[DudeWhatAreMyStats] Could not send the stored roster: " + ex.Message)); } } private static void RPC_All(long sender, ZPackage pkg) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown try { if (pkg == null) { return; } pkg.SetPos(0); if (pkg.ReadInt() != 1) { return; } int num = pkg.ReadInt(); Dictionary<long, Snapshot> dictionary = new Dictionary<long, Snapshot>(); for (int i = 0; i < num; i++) { Snapshot snapshot = Snapshot.Unpack(new ZPackage(pkg.ReadByteArray())); if (snapshot != null) { snapshot.IsLocal = false; snapshot.FromStore = true; snapshot.Online = false; dictionary[snapshot.Identity] = snapshot; } } _stored.Clear(); foreach (KeyValuePair<long, Snapshot> item in dictionary) { _stored[item.Key] = item.Value; } _serverAnswered = true; StatsPanel.OnRosterRebuilt(); } catch (Exception ex) { DudeWhatAreMyStatsMod.Log.LogWarning((object)("[DudeWhatAreMyStats] Could not read the stored roster: " + ex.Message)); } } internal static List<Snapshot> Roster() { List<Snapshot> list = new List<Snapshot>(); HashSet<long> hashSet = new HashSet<long>(); Snapshot snapshot = (((Object)(object)Player.m_localPlayer != (Object)null) ? LocalStats.Read() : null); if (snapshot != null) { list.Add(snapshot); hashSet.Add(snapshot.Identity); } bool flag = ReadConnectedNames(); float num = ((Time.unscaledTime - _lastRequestAt < 3f) ? _prevRequestAt : _lastRequestAt); bool flag2 = DwamsConfig.RememberOfflinePlayers == null || DwamsConfig.RememberOfflinePlayers.Value; foreach (Snapshot value in _remote.Values) { if (hashSet.Add(value.Identity)) { value.Online = (flag ? IsConnected(value) : (value.ReceivedAt >= num - 0.5f)); if (value.Online || flag2) { list.Add(value); } } } foreach (Snapshot value2 in _stored.Values) { if (hashSet.Add(value2.Identity)) { value2.Online = flag && IsConnected(value2); if (value2.Online || flag2) { list.Add(value2); } } } return list; } private static bool ReadConnectedNames() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) _connected.Clear(); ZNet instance = ZNet.instance; List<PlayerInfo> list = (((Object)(object)instance != (Object)null) ? instance.GetPlayerList() : null); if (list == null) { return false; } foreach (PlayerInfo item in list) { if (!string.IsNullOrEmpty(item.m_name)) { _connected.Add(item.m_name); } } return _connected.Count > 0; } private static bool IsConnected(Snapshot snap) { if (!string.IsNullOrEmpty(snap.Name)) { return _connected.Contains(snap.Name); } return false; } } internal static class StatsPanel { private enum Tab { Scoreboard, Details } private sealed class Column { internal string Key; internal string Header; internal float Start; internal float End; internal Func<Snapshot, float> Sort; internal Func<Snapshot, string> Text; internal bool RightAlign = true; } private const float W = 820f; private const float H = 620f; private const float MinW = 620f; private const float MaxW = 1800f; private const float MinH = 400f; private const float MaxH = 1400f; private const float HeaderHeight = 26f; private const float ListTop = 152f; private static GameObject _root; private static RectTransform _content; private static TextMeshProUGUI _title; private static TextMeshProUGUI _subtitle; private static Button _tabScore; private static Button _tabDetails; private static Button _refreshButton; private static Button _closeButton; private static Button _expandAll; private static Button _collapseAll; private static Button _prevPlayer; private static Button _nextPlayer; private static TextMeshProUGUI _detailWho; private static RectTransform _headerRow; private static readonly List<TextMeshProUGUI> _headerLabels = new List<TextMeshProUGUI>(); private static RectTransform _listContent; private static ScrollRect _scroll; private static RectTransform _grip; private static RectTransform _mover; private static float _w = 820f; private static float _h = 620f; private static Tab _tab = Tab.Scoreboard; private static long _detailPlayer; private static List<Snapshot> _roster = new List<Snapshot>(); private static bool _dirty; private static bool _openedThisFrame; private static bool _buildFailed; private static int _closedFrame = -10; private static readonly HashSet<string> _collapsed = new HashSet<string>(StringComparer.Ordinal); private static bool _collapsedLoaded; private static bool _scrollReset = true; private static readonly Column[] Columns = new Column[7] { new Column { Key = "Player", Header = "Player", Start = 0f, End = 0.26f, RightAlign = false, Sort = null, Text = (Snapshot s) => s.Name }, new Column { Key = "Kills", Header = "Kills", Start = 0.26f, End = 0.38f, Sort = (Snapshot s) => s.Kills, Text = (Snapshot s) => StatGroups.Count(s.Kills) }, new Column { Key = "Deaths", Header = "Deaths", Start = 0.38f, End = 0.49f, Sort = (Snapshot s) => s.Deaths, Text = (Snapshot s) => StatGroups.Count(s.Deaths) }, new Column { Key = "K/D", Header = "K/D", Start = 0.49f, End = 0.59f, Sort = (Snapshot s) => s.KillDeath, Text = (Snapshot s) => s.KillDeath.ToString("0.0") }, new Column { Key = "Bosses", Header = "Bosses", Start = 0.59f, End = 0.7f, Sort = (Snapshot s) => s.Bosses, Text = (Snapshot s) => StatGroups.Count(s.Bosses) }, new Column { Key = "Played", Header = "Played", Start = 0.7f, End = 0.84f, Sort = (Snapshot s) => s.Played, Text = (Snapshot s) => StatGroups.Duration(s.Played) }, new Column { Key = "Skill", Header = "Best skill", Start = 0.84f, End = 1f, Sort = (Snapshot s) => s.BestSkillLevel, Text = (Snapshot s) => s.BestSkillText } }; internal static bool IsOpen { get { if ((Object)(object)_root != (Object)null) { return _root.activeSelf; } return false; } } internal static bool JustClosed => Time.frameCount - _closedFrame <= 1; internal static void Toggle() { if (IsOpen) { Close(); } else { Open(); } } internal static void Open() { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { if ((Object)(object)_root == (Object)null && !Build()) { DudeWhatAreMyStatsMod.Message("Stats panel unavailable; try dwams_status in the console."); return; } LoadCollapsed(); _root.SetActive(true); _root.transform.SetAsLastSibling(); _openedThisFrame = true; StatsPause.Refresh(); StatsNetwork.RequestNow(); StatsNetwork.PushLocal(); _scrollReset = true; Populate(); _dirty = false; } } internal static void Close() { if ((Object)(object)_root != (Object)null && _root.activeSelf) { _root.SetActive(false); _closedFrame = Time.frameCount; } StatsPause.Refresh(); } internal static void OnRosterChanged(long identity) { if (!IsOpen || _tab != Tab.Details || identity == _detailPlayer) { _dirty = true; } } internal static void OnRosterRebuilt() { _dirty = true; } internal static void Update() { //IL_000c: 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) if (!IsOpen) { if (Keys.IsDown(DwamsConfig.OpenKey.Value) && Keys.CanTakeInput()) { Open(); } return; } if (_openedThisFrame) { _openedThisFrame = false; return; } if (Console.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) || UiKit.AnyFieldFocused()) { StatsPause.Refresh(); return; } if (ZInput.GetKeyDown((KeyCode)27, true) || Keys.IsDown(DwamsConfig.OpenKey.Value)) { Close(); return; } if (ZInput.GetKeyDown((KeyCode)9, true)) { SetTab((_tab == Tab.Scoreboard) ? Tab.Details : Tab.Scoreboard); return; } if (_tab == Tab.Details) { if (ZInput.GetKeyDown((KeyCode)276, true)) { StepPlayer(-1); return; } if (ZInput.GetKeyDown((KeyCode)275, true)) { StepPlayer(1); return; } } StatsPause.Refresh(); if (_dirty) { _dirty = false; Populate(); } SyncHeader(); } private static void Populate() { if (!((Object)(object)_listContent == (Object)null)) { _roster = StatsNetwork.Roster(); SortRoster(); UiKit.ClearChildren((Transform)(object)_listContent); if (_tab == Tab.Scoreboard) { PopulateScoreboard(); } else { PopulateDetails(); } UpdateChrome(); SyncHeader(); if (_scrollReset && (Object)(object)_scroll != (Object)null) { _scrollReset = false; _scroll.verticalNormalizedPosition = 1f; } } } private static void SyncHeader() { //IL_0038: 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) if (!((Object)(object)_headerRow == (Object)null) && !((Object)(object)_listContent == (Object)null) && ((Component)_headerRow).gameObject.activeSelf) { float num = 6f; Rect rect = _listContent.rect; float num2 = ((Rect)(ref rect)).width - num; if (!(num2 <= 0f)) { UiKit.Place(_headerRow, 30f + num, 124f, num2, 26f); } } } private static void PopulateScoreboard() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) if (_roster.Count == 0) { UiKit.Row((Transform)(object)_listContent, "No stats yet.", "", null, null, 17f, UiKit.Dim); return; } foreach (Snapshot item in _roster) { Snapshot captured = item; bool flag = !item.IsLocal && !item.Online; Color color = (item.IsLocal ? UiKit.Gold : (flag ? UiKit.Dim : UiKit.Body)); string lastSeenText = item.LastSeenText; string text = (item.IsLocal ? " (you)" : (flag ? (" (" + ((lastSeenText.Length > 0) ? lastSeenText : "offline") + ")") : "")); TableRow(item.Name + text, captured, color, delegate { ShowDetails(captured.Identity); }); } } private static void TableRow(string nameText, Snapshot snap, Color color, Action onClick) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Row", new Type[6] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Button), typeof(LayoutElement), typeof(UiKit.Hover) }); val.transform.SetParent((Transform)(object)_listContent, false); Image img = val.GetComponent<Image>(); ((Graphic)img).color = UiKit.RowColor; ((Graphic)img).raycastTarget = true; LayoutElement component = val.GetComponent<LayoutElement>(); component.preferredHeight = 28f; component.minHeight = 28f; Button component2 = val.GetComponent<Button>(); ((Selectable)component2).transition = (Transition)0; ((Selectable)component2).targetGraphic = (Graphic)(object)img; if (onClick != null) { ((UnityEvent)component2.onClick).AddListener((UnityAction)delegate { onClick(); }); } val.GetComponent<UiKit.Hover>().OnHoverChanged = delegate(bool on) { //IL_001e: 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) if ((Object)(object)img != (Object)null) { ((Graphic)img).color = (on ? UiKit.RowHover : UiKit.RowColor); } }; for (int num = 0; num < Columns.Length; num++) { Column column = Columns[num]; string text = ((num == 0) ? nameText : column.Text(snap)); SpanColumn(((TMP_Text)UiKit.Text(val.transform, column.Key, text, 17f, (TextAlignmentOptions)(column.RightAlign ? 516 : 513), color)).rectTransform, column); } } private static void SpanColumn(RectTransform rt, Column col) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) rt.anchorMin = new Vector2(col.Start, 0f); rt.anchorMax = new Vector2(col.End, 1f); rt.pivot = new Vector2(0.5f, 0.5f); rt.offsetMin = new Vector2(6f, 0f); rt.offsetMax = new Vector2(-6f, 0f); } private static void PopulateDetails() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Invalid comparison between Unknown and I4 //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Invalid comparison between Unknown and I4 //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) Snapshot snap = Current(); if (snap == null) { UiKit.Row((Transform)(object)_listContent, "No stats yet.", "", null, null, 17f, UiKit.Dim); return; } Section("Summary", delegate { UiKit.Row((Transform)(object)_listContent, "Kills", StatGroups.Count(snap.Kills), null, null); UiKit.Row((Transform)(object)_listContent, "Deaths", StatGroups.Count(snap.Deaths), null, null); UiKit.Row((Transform)(object)_listContent, "Kills per death", snap.KillDeath.ToString("0.0"), null, null); UiKit.Row((Transform)(object)_listContent, "Boss kills", StatGroups.Count(snap.Bosses), null, null); UiKit.Row((Transform)(object)_listContent, "Time played", StatGroups.Duration(snap.Played), null, null); UiKit.Row((Transform)(object)_listContent, "Skill levels total", StatGroups.Count(snap.SkillTotal), null, null); }); if (snap.Skills.Count > 0) { Section("Skills", delegate { //IL_0022: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair<SkillType, float> skill in snap.Skills) { UiKit.Row((Transform)(object)_listContent, Snapshot.SkillName(skill.Key), skill.Value.ToString("0.0"), null, null); } }); } bool flag = DwamsConfig.ShowZeroStats != null && DwamsConfig.ShowZeroStats.Value; Dictionary<string, List<KeyValuePair<PlayerStatType, float>>> dictionary = new Dictionary<string, List<KeyValuePair<PlayerStatType, float>>>(StringComparer.Ordinal); foreach (PlayerStatType value3 in Enum.GetValues(typeof(PlayerStatType))) { if ((int)value3 == 205 || (int)value3 == 206) { continue; } float num = snap.Stat(value3); if (num != 0f || flag) { string key = StatGroups.Section(value3); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List<KeyValuePair<PlayerStatType, float>>()); } value.Add(new KeyValuePair<PlayerStatType, float>(value3, num)); } } string[] order = StatGroups.Order; foreach (string text in order) { if (!dictionary.TryGetValue(text, out var value2) || value2.Count == 0) { continue; } value2.Sort((KeyValuePair<PlayerStatType, float> a, KeyValuePair<PlayerStatType, float> b) => string.Compare(StatGroups.Label(a.Key), StatGroups.Label(b.Key), StringComparison.Ordinal)); List<KeyValuePair<PlayerStatType, float>> captured = value2; Section(text, delegate { //IL_001d: 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) foreach (KeyValuePair<PlayerStatType, float> item in captured) { UiKit.Row((Transform)(object)_listContent, StatGroups.Label(item.Key), StatGroups.Format(item.Key, item.Value), null, null); } }); } if (((DwamsConfig.TopCreatureCount != null) ? DwamsConfig.TopCreatureCount.Value : 15) <= 0 || snap.Creatures.Count <= 0) { return; } Section("Creatures killed", delegate { foreach (KeyValuePair<string, float> creature in snap.Creatures) { UiKit.Row((Transform)(object)_listContent, CreatureName(creature.Key), StatGroups.Count(creature.Value), null, null); } }); } private static void Section(string title, Action body) { bool flag = _collapsed.Contains(title); UiKit.SectionHeader((Transform)(object)_listContent, title, delegate { if (!_collapsed.Remove(title)) { _collapsed.Add(title); } SaveCollapsed(); _dirty = true; }, flag); if (!flag) { body(); } } private static string CreatureName(string key) { if (string.IsNullOrEmpty(key)) { return "(unknown)"; } if (key.StartsWith("$", StringComparison.Ordinal) && Localization.instance != null) { string text = Localization.instance.Localize(key); if (!string.IsNullOrEmpty(text) && text != key && !text.StartsWith("[", StringComparison.Ordinal)) { return text; } } return key.TrimStart(new char[1] { '$' }); } private static Column SortColumn() { string b = ((DwamsConfig.SortColumn != null) ? DwamsConfig.SortColumn.Value : "Kills"); Column[] columns = Columns; foreach (Column column in columns) { if (string.Equals(column.Key, b, StringComparison.OrdinalIgnoreCase)) { return column; } } return Columns[1]; } private static void SortRoster() { Column col = SortColumn(); bool desc = DwamsConfig.SortDescending == null || DwamsConfig.SortDescending.Value; _roster.Sort(delegate(Snapshot a, Snapshot b) { int num = ((col.Sort == null) ? string.Compare(a.Name ?? "", b.Name ?? "", StringComparison.OrdinalIgnoreCase) : col.Sort(a).CompareTo(col.Sort(b))); if (num == 0) { num = string.Compare(a.Name ?? "", b.Name ?? "", StringComparison.OrdinalIgnoreCase); } return (!desc) ? num : (-num); }); } private static void OnHeaderClicked(Column col) { if (DwamsConfig.SortColumn != null) { if (string.Equals(DwamsConfig.SortColumn.Value, col.Key, StringComparison.OrdinalIgnoreCase)) { DwamsConfig.SortDescending.Value = !DwamsConfig.SortDescending.Value; } else { DwamsConfig.SortColumn.Value = col.Key; DwamsConfig.SortDescending.Value = col.Sort != null; } _scrollReset = true; _dirty = true; } } private static Snapshot Current() { foreach (Snapshot item in _roster) { if (item.Identity == _detailPlayer) { return item; } } foreach (Snapshot item2 in _roster) { if (item2.IsLocal) { return item2; } } if (_roster.Count <= 0) { return null; } return _roster[0]; } private static void ShowDetails(long identity) { _detailPlayer = identity; _scrollReset = true; SetTab(Tab.Details); } private static void StepPlayer(int delta) { if (_roster.Count != 0) { Snapshot snapshot = Current(); int num = ((snapshot != null) ? _roster.IndexOf(snapshot) : 0); num = ((num + delta) % _roster.Count + _roster.Count) % _roster.Count; _detailPlayer = _roster[num].Identity; _scrollReset = true; _dirty = true; } } private static void SetTab(Tab tab) { if (_tab != tab) { _scrollReset = true; } _tab = tab; if (tab == Tab.Details && _detailPlayer == 0L) { Snapshot snapshot = Current(); if (snapshot != null) { _detailPlayer = snapshot.Identity; } } _dirty = true; } private static void UpdateChrome() { //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_subtitle != (Object)null) { int num = 0; foreach (Snapshot item in _roster) { if (item.IsLocal || item.Online) { num++; } } string text = ((StatsPause.Holding && (Object)(object)ZNet.instance != (Object)null && Game.IsPaused()) ? " · game paused" : ""); string text2 = ((DwamsConfig.AskOtherPlayers != null && !DwamsConfig.AskOtherPlayers.Value) ? " · not asking other players" : ""); ((TMP_Text)_subtitle).text = string.Format("{0} player{1}{2}{3}", num, (num == 1) ? "" : "s", text, text2); } if ((Object)(object)_tabScore != (Object)null) { UiKit.SetLabel(((Component)_tabScore).gameObject, (_tab == Tab.Scoreboard) ? "<b>Scoreboard</b>" : "Scoreboard"); } if ((Object)(object)_tabDetails != (Object)null) { UiKit.SetLabel(((Component)_tabDetails).gameObject, (_tab == Tab.Details) ? "<b>Details</b>" : "Details"); } bool flag = _tab == Tab.Details; if ((Object)(object)_headerRow != (Object)null) { ((Component)_headerRow).gameObject.SetActive(!flag); } if ((Object)(object)_expandAll != (Object)null) { ((Component)_expandAll).gameObject.SetActive(flag); } if ((Object)(object)_collapseAll != (Object)null) { ((Component)_collapseAll).gameObject.SetActive(flag); } if ((Object)(object)_prevPlayer != (Object)null) { ((Component)_prevPlayer).gameObject.SetActive(flag && _roster.Count > 1); } if ((Object)(object)_nextPlayer != (Object)null) { ((Component)_nextPlayer).gameObject.SetActive(flag && _roster.Count > 1); } if ((Object)(object)_detailWho != (Object)null) { ((Component)_detailWho).gameObject.SetActive(flag); Snapshot snapshot = Current(); ((TMP_Text)_detailWho).text = ((snapshot == null) ? "" : (snapshot.Name + (snapshot.IsLocal ? " (you)" : (snapshot.Online ? "" : " (offline)")))); } if (!flag) { Column column = SortColumn(); bool flag2 = DwamsConfig.SortDescending == null || DwamsConfig.SortDescending.Value; for (int i = 0; i < _headerLabels.Count && i < Columns.Length; i++) { bool flag3 = Columns[i] == column; ((TMP_Text)_headerLabels[i]).text = Columns[i].Header + (flag3 ? (flag2 ? " ▼" : " ▲") : ""); ((Graphic)_headerLabels[i]).color = (flag3 ? UiKit.Gold : UiKit.Header); } } } private static bool Build() { if (_buildFailed) { return false; } try { if (BuildInner()) { return true; } } catch (Exception arg) { DudeWhatAreMyStatsMod.Log.LogError((object)$"[DudeWhatAreMyStats] Building the stats panel failed: {arg}"); _buildFailed = true; } if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } _root = null; return false; } private static bool BuildInner() { //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0208: 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_0228: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Unknown result type (might be due to invalid IL or missing references) //IL_04b2: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Expected O, but got Unknown //IL_0550: Unknown result type (might be due to invalid IL or missing references) //IL_0555: Unknown result type (might be due to invalid IL or missing references) //IL_0567: Unknown result type (might be due to invalid IL or missing references) //IL_0582: Unknown result type (might be due to invalid IL or missing references) //IL_0592: Unknown result type (might be due to invalid IL or missing references) //IL_05ac: Unknown result type (might be due to invalid IL or missing references) //IL_05b6: Expected O, but got Unknown //IL_05b6: Unknown result type (might be due to invalid IL or missing references) //IL_05ee: Unknown result type (might be due to invalid IL or missing references) //IL_06b0: Unknown result type (might be due to invalid IL or missing references) //IL_06b5: Unknown result type (might be due to invalid IL or missing references) //IL_06c7: Unknown result type (might be due to invalid IL or missing references) //IL_06d2: Unknown result type (might be due to invalid IL or missing references) //IL_06f8: Unknown result type (might be due to invalid IL or missing references) //IL_078d: Unknown result type (might be due to invalid IL or missing references) //IL_0792: Unknown result type (might be due to invalid IL or missing references) //IL_07a4: Unknown result type (might be due to invalid IL or missing references) //IL_07af: Unknown result type (might be due to invalid IL or missing references) //IL_07ca: Unknown result type (might be due to invalid IL or missing references) TextInput instance = TextInput.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_panel == (Object)null) { DudeWhatAreMyStatsMod.Log.LogWarning((object)"[DudeWhatAreMyStats] The game's text prompt is not available; cannot build the stats panel."); return false; } UiKit.EnsureFont(); _root = Object.Instantiate<GameObject>(instance.m_panel, instance.m_panel.transform.parent); ((Object)_root).name = "DWAMS_StatsPanel"; _root.SetActive(false); LayoutGroup[] components = _root.GetComponents<LayoutGroup>(); int i; for (i = 0; i < components.Length; i++) { Object.Destroy((Object)(object)components[i]); } ContentSizeFitter[] components2 = _root.GetComponents<ContentSizeFitter>(); for (i = 0; i < components2.Length; i++) { Object.Destroy((Object)(object)components2[i]); } Button val = null; Button[] componentsInChildren = _root.GetComponentsInChildren<Button>(true); i = 0; if (i < componentsInChildren.Length) { val = componentsInChildren[i]; } GameObject val2 = new GameObject("DWAMS_Content", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(_root.transform, false); UiKit.Stretch(val2.GetComponent<RectTransform>()); _content = val2.GetComponent<RectTransform>(); if ((Object)(object)val != (Object)null) { val = Object.Instantiate<Button>(val, val2.transform); ((Component)val).gameObject.SetActive(false); ((Object)val).name = "ButtonTemplate"; } for (int num = _root.transform.childCount - 1; num >= 0; num--) { Transform child = _root.transform.GetChild(num); if (!((Object)(object)child == (Object)(object)val2.transform)) { if (IsDecoration(child)) { child.SetParent(val2.transform, false); child.SetAsFirstSibling(); UiKit.Stretch(((Component)child).GetComponent<RectTransform>()); } else { Object.Destroy((Object)(object)((Component)child).gameObject); } } } RectTransform component = _root.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = Vector2.zero; component.sizeDelta = new Vector2(820f, 620f); _title = UiKit.Text(val2.transform, "Title", "Dude, What Are My Stats?", 26f, (TextAlignmentOptions)514, UiKit.Gold); _subtitle = UiKit.Text(val2.transform, "Subtitle", "", 15f, (TextAlignmentOptions)514, UiKit.Dim); _tabScore = MakeButton(val, val2.transform, "TabScoreboard", "Scoreboard", delegate { SetTab(Tab.Scoreboard); }); _tabDetails = MakeButton(val, val2.transform, "TabDetails", "Details", delegate { SetTab(Tab.Details); }); _refreshButton = MakeButton(val, val2.transform, "Refresh", "Refresh", delegate { StatsNetwork.RequestNow(); _dirty = true; }); _closeButton = MakeButton(val, val2.transform, "Close", "Close", Close); _prevPlayer = MakeButton(val, val2.transform, "PrevPlayer", "<", delegate { StepPlayer(-1); }); _nextPlayer = MakeButton(val, val2.transform, "NextPlayer", ">", delegate { StepPlayer(1); }); _detailWho = UiKit.Text(val2.transform, "DetailWho", "", 19f, (TextAlignmentOptions)514, UiKit.Gold); _expandAll = UiKit.LinkButton(val2.transform, "ExpandAll", "Expand all", delegate { _collapsed.Clear(); SaveCollapsed(); _dirty = true; }); _collapseAll = UiKit.LinkButton(val2.transform, "CollapseAll", "Collapse all", delegate { _collapsed.Clear(); _collapsed.Add("Summary"); _collapsed.Add("Skills"); _collapsed.Add("Creatures killed"); string[] order = StatGroups.Order; foreach (string item in order) { _collapsed.Add(item); } SaveCollapsed(); _dirty = true; }); GameObject val3 = new GameObject("Headers", new Type[1] { typeof(RectTransform) }); val3.transform.SetParent(val2.transform, false); _headerRow = val3.GetComponent<RectTransform>(); _headerLabels.Clear(); Column[] columns = Columns; foreach (Column column in columns) { Column captured = column; GameObject val4 = new GameObject("H_" + column.Key, new Type[4] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Button) }); val4.transform.SetParent(val3.transform, false); Image component2 = val4.GetComponent<Image>(); ((Graphic)component2).color = new Color(1f, 1f, 1f, 0.04f); ((Graphic)component2).raycastTarget = true; Button component3 = val4.GetComponent<Button>(); ((Selectable)component3).transition = (Transition)0; ((UnityEvent)component3.onClick).AddListener((UnityAction)delegate { OnHeaderClicked(captured); }); SpanColumn(val4.GetComponent<RectTransform>(), column); TextMeshProUGUI val5 = UiKit.Text(val4.transform, "Label", column.Header, 16f, (TextAlignmentOptions)(column.RightAlign ? 516 : 513), UiKit.Header); UiKit.Stretch(((TMP_Text)val5).rectTransform); _headerLabels.Add(val5); } _listContent = UiKit.ScrollList(val2.transform, "List", out _scroll); Localize[] componentsInChildren2 = _root.GetComponentsInChildren<Localize>(true); for (i = 0; i < componentsInChildren2.Length; i++) { Object.Destroy((Object)(object)componentsInChildren2[i]); } GameObject val6 = new GameObject("Grip", new Type[4] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(UiKit.DragHandle) }); val6.transform.SetParent(val2.transform, false); _grip = val6.GetComponent<RectTransform>(); Image component4 = val6.GetComponent<Image>(); component4.sprite = UiKit.Grip(); ((Graphic)component4).color = new Color(1f, 0.85f, 0.45f, 0.75f); ((Graphic)component4).raycastTarget = true; UiKit.DragHandle component5 = val6.GetComponent<UiKit.DragHandle>(); component5.OnDrag = OnGripDrag; component5.OnEnd = SavePlacement; GameObject val7 = new GameObject("Mover", new Type[4] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(UiKit.DragHandle) }); val7.transform.SetParent(val2.transform, false); _mover = val7.GetComponent<RectTransform>(); Image component6 = val7.GetComponent<Image>(); ((Graphic)component6).color = new Color(0f, 0f, 0f, 0f); ((Graphic)component6).raycastTarget = true; UiKit.DragHandle component7 = val7.GetComponent<UiKit.DragHandle>(); component7.OnDrag = OnMoveDrag; component7.OnEnd = SavePlacement; LoadPlacement(); Layout(); return true; } private static Button MakeButton(Button template, Transform parent, string name, string label, Action onClick) { if (!((Object)(object)template != (Object)null)) { return UiKit.SimpleButton(parent, name, label, onClick); } return UiKit.CloneButton(template, parent, name, label, onClick); } private static bool IsDecoration(Transform child) { if ((Object)(object)((Component)child).GetComponentInChildren<TMP_Text>(true) != (Object)null) { return false; } if ((Object)(object)((Component)child).GetComponentInChildren<Selectable>(true) != (Object)null) { return false; } if ((Object)(object)((Component)child).GetComponentInChildren<Graphic>(true) != (Object)null) { return (Object)(object)((Component)child).GetComponent<RectTransform>() != (Object)null; } return false; } private static void Layout() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root == (Object)null)) { float w = _w; float h = _h; _root.GetComponent<RectTransform>().sizeDelta = new Vector2(w, h); if ((Object)(object)_title != (Object)null) { UiKit.Place(((TMP_Text)_title).rectTransform, 0f, 14f, w, 34f); } if ((Object)(object)_subtitle != (Object)null) { UiKit.Place(((TMP_Text)_subtitle).rectTransform, 0f, 48f, w, 22f); } float y = 76f; float h2 = 34f; if ((Object)(object)_tabScore != (Object)null) { UiKit.Place(((Component)_tabScore).GetComponent<RectTransform>(), 30f, y, 140f, h2); } if ((Object)(object)_tabDetails != (Object)null) { UiKit.Place(((Component)_tabDetails).GetComponent<RectTransform>(), 178f, y, 140f, h2); } if ((Object)(object)_refreshButton != (Object)null) { UiKit.Place(((Component)_refreshButton).GetComponent<RectTransform>(), w - 290f, y, 120f, h2); } if ((Object)(object)_closeButton != (Object)null) { UiKit.Place(((Component)_closeButton).GetComponent<RectTransform>(), w - 160f, y, 120f, h2); } float num = 118f; float num2 = Mathf.Max(120f, w - 380f); if ((Object)(object)_prevPlayer != (Object)null) { UiKit.Place(((Component)_prevPlayer).GetComponent<RectTransform>(), 30f, num, 36f, 28f); } if ((Object)(object)_detailWho != (Object)null) { UiKit.Place(((TMP_Text)_detailWho).rectTransform, 74f, num, num2, 28f); } if ((Object)(object)_nextPlayer != (Object)null) { UiKit.Place(((Component)_nextPlayer).GetComponent<RectTransform>(), 74f + num2 + 6f, num, 36f, 28f); } if ((Object)(object)_expandAll != (Object)null) { UiKit.Place(((Component)_expandAll).GetComponent<RectTransform>(), w - 202f, num + 4f, 82f, 22f); } if ((Object)(object)_collapseAll != (Object)null) { UiKit.Place(((Component)_collapseAll).GetComponent<RectTransform>(), w - 116f, num + 4f, 86f, 22f); } if ((Object)(object)_scroll != (Object)null) { UiKit.Place(((Component)_scroll).GetComponent<RectTransform>(), 30f, 152f, w - 60f, h - 152f - 30f); } SyncHeader(); if ((Object)(object)_mover != (Object)null) { UiKit.Place(_mover, 0f, 0f, w, 70f); } if ((Object)(object)_grip != (Object)null) { _grip.anchorMin = new Vector2(1f, 0f); _grip.anchorMax = new Vector2(1f, 0f); _grip.pivot = new Vector2(1f, 0f); _grip.anchoredPosition = new Vector2(-5f, 5f); _grip.sizeDelta = new Vector2(18f, 18f); } } } private static void OnGripDrag(Vector2 screenDelta) { //IL_0019: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root == (Object)null)) { float num = CanvasScale(); float num2 = Mathf.Clamp(_w + screenDelta.x / num, 620f, 1800f); float num3 = Mathf.Clamp(_h - screenDelta.y / num, 400f, 1400f); RectTransform component = _root.GetComponent<RectTransform>(); component.anchoredPosition += new Vector2((num2 - _w) / 2f, (0f - (num3 - _h)) / 2f); _w = num2; _h = num3; Layout(); } } private static void OnMoveDrag(Vector2 screenDelta) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_002a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root == (Object)null)) { RectTransform co