using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ComputerysModdingUtilities; using HarmonyLib; using Microsoft.CodeAnalysis; using Steamworks; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: StraftatMod(true)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.0.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 LobbyRanks { [BepInPlugin("landa.straftat.lobbyranks", "Lobby Ranks", "1.2.1")] public class Plugin : BaseUnityPlugin { internal const string DefaultWhitelistUrl = "https://raw.githubusercontent.com/C0mputery/StraftatLeaderboardWhitelist/refs/heads/main/Whitelist"; internal static ManualLogSource Log; internal static ConfigEntry Enabled; internal static ConfigEntry ShowScore; internal static ConfigEntry HighlightSelf; internal static ConfigEntry CheaterAdjusted; internal static ConfigEntry PanelX; internal static ConfigEntry PanelY; internal static ConfigEntry Scale; internal static ConfigEntry ToggleKey; internal static ConfigEntry ApiNameOverride; internal static ConfigEntry WhitelistUrl; private void Awake() { //IL_00a5: 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) //IL_00f1: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown //IL_01c8: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("LobbyRanks.Display", "Enabled", true, "Master toggle for the lobby rank panel."); ShowScore = ((BaseUnityPlugin)this).Config.Bind("LobbyRanks.Display", "ShowScore", true, "Show each player's raw leaderboard score (gamesWon*4 + roundsWon) beside their global rank."); HighlightSelf = ((BaseUnityPlugin)this).Config.Bind("LobbyRanks.Display", "HighlightYou", true, "Tint your own row so you can spot it at a glance."); CheaterAdjusted = ((BaseUnityPlugin)this).Config.Bind("LobbyRanks.Display", "CheaterAdjusted", true, "Adjust ranks for known cheaters using C0mputery's whitelist so they match the in-game leaderboard. Players sitting in the top ranks who aren't on the whitelist are flagged. Turn off to show Steam's raw global rank instead."); ToggleKey = ((BaseUnityPlugin)this).Config.Bind("LobbyRanks.Display", "ToggleKey", new KeyboardShortcut((KeyCode)291, Array.Empty()), "Hotkey to show/hide the panel."); PanelX = ((BaseUnityPlugin)this).Config.Bind("LobbyRanks.Panel", "CenterX", 0.5f, new ConfigDescription("Panel horizontal center as a fraction of screen width.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); PanelY = ((BaseUnityPlugin)this).Config.Bind("LobbyRanks.Panel", "TopY", 0.1f, new ConfigDescription("Panel top edge as a fraction of screen height.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.9f), Array.Empty())); Scale = ((BaseUnityPlugin)this).Config.Bind("LobbyRanks.Panel", "Scale", 1f, new ConfigDescription("Panel scale.", (AcceptableValueBase)(object)new AcceptableValueRange(0.6f, 2f), Array.Empty())); ApiNameOverride = ((BaseUnityPlugin)this).Config.Bind("LobbyRanks.Advanced", "LeaderboardApiName", "", "Leave blank to use the same leaderboard the game itself resolved (read off its LeaderboardManager). Only set this if that fails - the resolved name is logged once at startup."); WhitelistUrl = ((BaseUnityPlugin)this).Config.Bind("LobbyRanks.Advanced", "WhitelistUrl", "https://raw.githubusercontent.com/C0mputery/StraftatLeaderboardWhitelist/refs/heads/main/Whitelist", "URL of the newline-delimited SteamID64 whitelist used to filter cheaters out of the ranking."); GameObject val = new GameObject("LobbyRanks"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Lobby Ranks loaded."); } } internal enum RankKind { BoardPending, Unranked, Provisional, Top10, Normal, Cheater } internal struct PlayerRow { public ulong SteamId; public string Name; public bool IsLocal; public int Rank; public int Score; public bool Ranked; } internal static class Ranks { private enum State { Idle, Finding, Ready, Failed } private static State _state = State.Idle; private static SteamLeaderboard_t _board; private static string _apiName; private static float _retryAt = -999f; private static CallResult _findCall; private static CallResult _downloadCall; private static readonly Dictionary _cache = new Dictionary(); private static HashSet _lastRequested = new HashSet(); private static readonly HashSet _requestScratch = new HashSet(); private static readonly HashSet _downloadedScratch = new HashSet(); private static readonly List _pruneKeys = new List(); private static bool _requestInFlight; private static float _lastRequestAt = -999f; private static int _dataVersion; private const float MinRequestInterval = 4f; private static readonly Dictionary _top10Rank = new Dictionary(); private static int _rankOffset; private static bool _normReady; internal const int MaxUsersPerRequest = 100; internal static bool BoardReady => _state == State.Ready; internal static SteamLeaderboard_t Board => _board; internal static int DataVersion => _dataVersion; internal static void EnsureBoard(float now) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) if (_state == State.Finding || _state == State.Ready || (_state == State.Failed && now < _retryAt)) { return; } string text = ResolveApiName(); if (string.IsNullOrEmpty(text)) { _state = State.Failed; _retryAt = now + 15f; return; } try { if (_findCall == null) { _findCall = CallResult.Create((APIDispatchDelegate)OnFind); } _apiName = text; _state = State.Finding; _retryAt = now + 15f; SteamAPICall_t val = SteamUserStats.FindLeaderboard(text); _findCall.Set(val, (APIDispatchDelegate)null); Plugin.Log.LogInfo((object)("[LobbyRanks] Looking up leaderboard '" + text + "'...")); } catch (Exception ex) { _state = State.Failed; _retryAt = now + 15f; Plugin.Log.LogWarning((object)("[LobbyRanks] FindLeaderboard deferred: " + ex.Message)); } } private static void OnFind(LeaderboardFindResult_t result, bool ioFailure) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (ioFailure || result.m_bLeaderboardFound == 0) { _state = State.Failed; _dataVersion++; Plugin.Log.LogWarning((object)$"[LobbyRanks] Leaderboard '{_apiName}' not found (ioFailure={ioFailure})."); } else { _board = result.m_hSteamLeaderboard; _state = State.Ready; _dataVersion++; Plugin.Log.LogInfo((object)("[LobbyRanks] Leaderboard '" + _apiName + "' resolved.")); } } internal static void Refresh(IReadOnlyList roster, float now) { //IL_00c4: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) if (_state != State.Ready || _requestInFlight || roster.Count == 0) { return; } _requestScratch.Clear(); int num = Math.Min(roster.Count, 100); for (int i = 0; i < num; i++) { _requestScratch.Add(roster[i]); } if ((_requestScratch.SetEquals(_lastRequested) && now - _lastRequestAt < 30f) || now - _lastRequestAt < 4f) { return; } try { if (_downloadCall == null) { _downloadCall = CallResult.Create((APIDispatchDelegate)OnDownload); } CSteamID[] array = (CSteamID[])(object)new CSteamID[num]; for (int j = 0; j < num; j++) { array[j] = new CSteamID(roster[j]); } SteamAPICall_t val = SteamUserStats.DownloadLeaderboardEntriesForUsers(_board, array, array.Length); _downloadCall.Set(val, (APIDispatchDelegate)null); _requestInFlight = true; _lastRequested.Clear(); foreach (ulong item in _requestScratch) { _lastRequested.Add(item); } _lastRequestAt = now; } catch (Exception ex) { _requestInFlight = false; Plugin.Log.LogWarning((object)("[LobbyRanks] Download request failed: " + ex.Message)); } } private static void OnDownload(LeaderboardScoresDownloaded_t result, bool ioFailure) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) _requestInFlight = false; if (ioFailure) { Plugin.Log.LogWarning((object)"[LobbyRanks] Leaderboard download failed (ioFailure)."); return; } _downloadedScratch.Clear(); LeaderboardEntry_t val = default(LeaderboardEntry_t); for (int i = 0; i < result.m_cEntryCount; i++) { if (SteamUserStats.GetDownloadedLeaderboardEntry(result.m_hSteamLeaderboardEntries, i, ref val, (int[])null, 0)) { ulong steamID = val.m_steamIDUser.m_SteamID; _downloadedScratch.Add(steamID); _cache[steamID] = new PlayerRow { SteamId = steamID, Rank = val.m_nGlobalRank, Score = val.m_nScore, Ranked = true }; } } foreach (ulong item in _lastRequested) { if (!_downloadedScratch.Contains(item)) { _cache[item] = new PlayerRow { SteamId = item, Rank = 0, Score = 0, Ranked = false }; } } _pruneKeys.Clear(); foreach (ulong key in _cache.Keys) { if (!_lastRequested.Contains(key)) { _pruneKeys.Add(key); } } foreach (ulong pruneKey in _pruneKeys) { _cache.Remove(pruneKey); } _dataVersion++; } internal static bool TryGet(ulong id, out PlayerRow row) { return _cache.TryGetValue(id, out row); } internal static void SetNormalization(Dictionary top10, int offset) { _top10Rank.Clear(); foreach (KeyValuePair item in top10) { _top10Rank[item.Key] = item.Value; } _rankOffset = offset; _normReady = true; _dataVersion++; } internal static (string text, RankKind kind) Display(ulong steamId, int rawRank, bool ranked) { if (!BoardReady) { return (text: "…", kind: RankKind.BoardPending); } if (!ranked || rawRank <= 0) { return (text: "—", kind: RankKind.Unranked); } if (!Plugin.CheaterAdjusted.Value) { return (text: "#" + rawRank.ToString("N0"), kind: RankKind.Normal); } if (!_normReady) { return (text: "~" + rawRank.ToString("N0"), kind: RankKind.Provisional); } if (_top10Rank.TryGetValue(steamId, out var value)) { return (text: "#" + value.ToString("N0"), kind: RankKind.Top10); } int num = rawRank - _rankOffset; if (num > 10) { return (text: "#" + num.ToString("N0"), kind: RankKind.Normal); } return (text: "!" + rawRank.ToString("N0"), kind: RankKind.Cheater); } private static string ResolveApiName() { string value = Plugin.ApiNameOverride.Value; if (!string.IsNullOrEmpty(value)) { return value; } string text = ReadGameLeaderboardApiName(); if (!string.IsNullOrEmpty(text)) { return text; } Type type = AccessTools.TypeByName("HeathenEngineering.SteamworksIntegration.LeaderboardObject"); if (type == null) { return null; } FieldInfo fieldInfo = AccessTools.Field(type, "apiName"); if (fieldInfo == null) { return null; } Object[] array = Resources.FindObjectsOfTypeAll(type); foreach (Object obj in array) { if (fieldInfo.GetValue(obj) is string text2 && !string.IsNullOrEmpty(text2) && !text2.Equals("TestLeaderboard", StringComparison.OrdinalIgnoreCase)) { return text2; } } return null; } private static string ReadGameLeaderboardApiName() { try { Type type = AccessTools.TypeByName("Settings"); if (type == null) { return null; } object obj = AccessTools.Field(type, "Instance")?.GetValue(null); if (obj == null) { return null; } object obj2 = AccessTools.Field(type, "leaderboardManager")?.GetValue(obj); if (obj2 == null) { return null; } object obj3 = AccessTools.Field(obj2.GetType(), "leaderboard")?.GetValue(obj2); if (obj3 == null) { return null; } return AccessTools.Field(obj3.GetType(), "apiName")?.GetValue(obj3) as string; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[LobbyRanks] Could not read the game's leaderboard name: " + ex.Message)); return null; } } } internal class LobbyRanksBehaviour : MonoBehaviour { private sealed class DisplayRow { public PlayerRow Player; public RankKind RankKind; public readonly GUIContent RankContent = new GUIContent(); public readonly GUIContent NameContent = new GUIContent(); public readonly GUIContent ScoreContent = new GUIContent(); public float RankWidth; public float NameWidth; public float ScoreWidth; } private static FieldInfo _instancesField; private static FieldInfo _steamIdField; private static FieldInfo _nameField; private bool _reflectionReady; private bool _reflectionFailed; private ulong _localSteamId; private float _nextRosterPoll; private bool _hidden; private bool _normStarted; private readonly List _roster = new List(); private readonly List _steamIds = new List(); private readonly List _sortedRoster = new List(); private readonly List _displayRows = new List(); private readonly GUIContent _titleContent = new GUIContent("LOBBY RANKS"); private readonly GUIContent _countContent = new GUIContent(); private int _displayCount; private float _rankColumnWidth; private float _nameColumnWidth; private float _scoreColumnWidth; private float _headerWidth; private bool _layoutDirty = true; private int _seenRanksVersion = -1; private bool _stylesBuilt; private float _stylesScale = -1f; private GUIStyle _title; private GUIStyle _count; private GUIStyle _rankText; private GUIStyle _name; private GUIStyle _score; private GUIStyle _muted; private Color _cPanel; private Color _cBorder; private Color _cZebra; private Color _cSelf; private Color _cAccent; private Color _cAccentDim; private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = Plugin.ToggleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _hidden = !_hidden; } if (ResolveReflection() && !(Time.unscaledTime < _nextRosterPoll)) { _nextRosterPoll = Time.unscaledTime + 1f; if (!Ranks.BoardReady) { Ranks.EnsureBoard(Time.unscaledTime); } if (Ranks.BoardReady && !_normStarted && Plugin.CheaterAdjusted.Value) { _normStarted = true; ((MonoBehaviour)this).StartCoroutine(BuildNormalization()); } int dataVersion = Ranks.DataVersion; PollRoster(); if (_seenRanksVersion != dataVersion) { _seenRanksVersion = dataVersion; _layoutDirty = true; } if (_steamIds.Count > 0) { Ranks.Refresh(_steamIds, Time.unscaledTime); } } } private IEnumerator BuildNormalization() { string value = Plugin.WhitelistUrl.Value; UnityWebRequest req = UnityWebRequest.Get(value); string text; try { yield return req.SendWebRequest(); if ((int)req.result != 1) { Plugin.Log.LogWarning((object)("[LobbyRanks] Whitelist fetch failed (" + req.error + "); showing raw ranks until it loads.")); _normStarted = false; yield break; } text = req.downloadHandler.text; } finally { ((IDisposable)req)?.Dispose(); } HashSet hashSet = new HashSet(); using (StringReader stringReader = new StringReader(text)) { string text2; while ((text2 = stringReader.ReadLine()) != null) { if (ulong.TryParse(text2.Trim(), out var result)) { hashSet.Add(result); } } } ulong[] whitelist = new ulong[hashSet.Count]; hashSet.CopyTo(whitelist); if (whitelist.Length == 0) { Plugin.Log.LogWarning((object)"[LobbyRanks] Whitelist was empty; showing raw ranks."); yield break; } Plugin.Log.LogInfo((object)$"[LobbyRanks] Whitelist loaded ({whitelist.Length} accounts); resolving ranks..."); Dictionary ranks = new Dictionary(); CallResult call = CallResult.Create((APIDispatchDelegate)null); for (int offset = 0; offset < whitelist.Length; offset += 100) { int num = Math.Min(100, whitelist.Length - offset); CSteamID[] array = (CSteamID[])(object)new CSteamID[num]; for (int i = 0; i < num; i++) { array[i] = new CSteamID(whitelist[offset + i]); } bool done = false; call.Set(SteamUserStats.DownloadLeaderboardEntriesForUsers(Ranks.Board, array, array.Length), (APIDispatchDelegate)delegate(LeaderboardScoresDownloaded_t res, bool ioFailure) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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) if (!ioFailure) { LeaderboardEntry_t val = default(LeaderboardEntry_t); for (int j = 0; j < res.m_cEntryCount; j++) { if (SteamUserStats.GetDownloadedLeaderboardEntry(res.m_hSteamLeaderboardEntries, j, ref val, (int[])null, 0) && val.m_nGlobalRank > 0) { ranks[val.m_steamIDUser.m_SteamID] = val.m_nGlobalRank; } } } done = true; }); yield return (object)new WaitUntil((Func)(() => done)); } if (ranks.Count == 0) { Plugin.Log.LogWarning((object)"[LobbyRanks] No whitelisted players were ranked; showing raw ranks."); yield break; } List> list = new List>(ranks); list.Sort((KeyValuePair left, KeyValuePair right) => left.Value.CompareTo(right.Value)); if (list.Count > 10) { list.RemoveRange(10, list.Count - 10); } Dictionary dictionary = new Dictionary(); for (int num2 = 0; num2 < list.Count; num2++) { dictionary[list[num2].Key] = num2 + 1; } int value2 = list[list.Count - 1].Value; int num3 = Math.Max(0, value2 - list.Count); Ranks.SetNormalization(dictionary, num3); Plugin.Log.LogInfo((object)$"[LobbyRanks] Ranks normalized: {list.Count} in true top-10, {num3} cheaters above them."); } private void PollRoster() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) _roster.Clear(); _steamIds.Clear(); if (_localSteamId == 0L) { try { _localSteamId = (ulong)SteamUser.GetSteamID(); } catch { } } if (!(_instancesField.GetValue(null) is IDictionary dictionary)) { return; } foreach (object value in dictionary.Values) { if (value == null) { continue; } ulong num = (ulong)_steamIdField.GetValue(value); if (num != 0L) { string name = (_nameField.GetValue(value) as string) ?? "?"; PlayerRow item = new PlayerRow { SteamId = num, Name = name, IsLocal = (num == _localSteamId) }; if (Ranks.TryGet(num, out var row)) { item.Rank = row.Rank; item.Score = row.Score; item.Ranked = row.Ranked; } _roster.Add(item); _steamIds.Add(num); } } _layoutDirty = true; } private bool ResolveReflection() { if (_reflectionReady) { return true; } if (_reflectionFailed) { return false; } Type type = AccessTools.TypeByName("ClientInstance"); if (type == null) { return false; } _instancesField = AccessTools.Field(type, "playerInstances"); _steamIdField = AccessTools.Field(type, "PlayerSteamID"); _nameField = AccessTools.Field(type, "PlayerName"); if (_instancesField == null || _steamIdField == null || _nameField == null) { _reflectionFailed = true; Plugin.Log.LogError((object)"[LobbyRanks] Could not resolve ClientInstance fields; mod disabled."); return false; } _reflectionReady = true; return true; } private void RebuildDisplayRows() { //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) _sortedRoster.Clear(); _sortedRoster.AddRange(_roster); _sortedRoster.Sort(CompareRows); _displayCount = _sortedRoster.Count; while (_displayRows.Count < _displayCount) { _displayRows.Add(new DisplayRow()); } float value = Plugin.Scale.Value; _rankColumnWidth = 24f * value; _scoreColumnWidth = 6f * value; _nameColumnWidth = 0f; for (int i = 0; i < _displayCount; i++) { PlayerRow player = _sortedRoster[i]; DisplayRow displayRow = _displayRows[i]; displayRow.Player = player; GUIContent rankContent = displayRow.RankContent; DisplayRow displayRow2 = displayRow; (string, RankKind) tuple = Ranks.Display(player.SteamId, player.Rank, player.Ranked); rankContent.text = tuple.Item1; displayRow2.RankKind = tuple.Item2; displayRow.ScoreContent.text = (player.Ranked ? (Plugin.ShowScore.Value ? player.Score.ToString("N0") : "") : (Ranks.BoardReady ? "unranked" : "")); displayRow.NameContent.text = player.Name + (player.IsLocal ? " (you)" : ""); displayRow.RankWidth = _rankText.CalcSize(displayRow.RankContent).x; displayRow.ScoreWidth = (player.Ranked ? _score : _muted).CalcSize(displayRow.ScoreContent).x; displayRow.NameWidth = _name.CalcSize(displayRow.NameContent).x; _rankColumnWidth = Mathf.Max(_rankColumnWidth, displayRow.RankWidth); _scoreColumnWidth = Mathf.Max(_scoreColumnWidth, displayRow.ScoreWidth); _nameColumnWidth = Mathf.Max(_nameColumnWidth, displayRow.NameWidth); } _countContent.text = _displayCount + ((_displayCount == 1) ? " player" : " players"); _headerWidth = _title.CalcSize(_titleContent).x + 16f * value + _count.CalcSize(_countContent).x; _seenRanksVersion = Ranks.DataVersion; _layoutDirty = false; } private static int CompareRows(PlayerRow left, PlayerRow right) { int num = ((!left.Ranked) ? 1 : 0).CompareTo((!right.Ranked) ? 1 : 0); if (num != 0) { return num; } if (left.Ranked && right.Ranked) { num = left.Rank.CompareTo(right.Rank); if (num != 0) { return num; } } return string.Compare(left.Name, right.Name, StringComparison.OrdinalIgnoreCase); } private void OnGUI() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Enabled.Value || _hidden || _roster.Count == 0) { return; } Event current = Event.current; if (current != null && (int)current.type != 7) { return; } BuildStyles(); if (_layoutDirty || _seenRanksVersion != Ranks.DataVersion) { RebuildDisplayRows(); } float value = Plugin.Scale.Value; float num = 12f * value; float num2 = 30f * value; float num3 = 36f * value; float num4 = 10f * value; float num5 = 9f * value; float num6 = 11f * value; int displayCount = _displayCount; float num7 = _rankColumnWidth + num5 * 2f; float num8 = Mathf.Min(_nameColumnWidth, 260f * value); float num9 = Mathf.Max(num7 + num4 + num8 + num4 + _scoreColumnWidth, _headerWidth); float num10 = Mathf.Min(Mathf.Max(248f * value, num * 2f + num9), (float)Screen.width - 8f); float num11 = num3 + (float)displayCount * num2 + num; float num12 = Mathf.Clamp(Plugin.PanelX.Value * (float)Screen.width - num10 / 2f, 0f, Mathf.Max(0f, (float)Screen.width - num10)); float num13 = Plugin.PanelY.Value * (float)Screen.height; Fill(new Rect(num12, num13, num10, num11), _cBorder, num6); Fill(new Rect(num12 + 1.5f, num13 + 1.5f, num10 - 3f, num11 - 3f), _cPanel, num6 - 1f); Rect val = new Rect(num12 + num, num13, num10 - num * 2f, num3); ShadowLabel(val, _titleContent, _title); GUI.Label(val, _countContent, _count); Fill(new Rect(num12 + num, num13 + num3 - 3f * value, num10 - num * 2f, 1.5f * value), _cAccentDim, 1f); float num14 = num12 + num + num7 + num4; float num15 = num12 + num10 - num; float num16 = num13 + num3; Rect r = default(Rect); for (int i = 0; i < displayCount; i++) { DisplayRow displayRow = _displayRows[i]; PlayerRow player = displayRow.Player; ((Rect)(ref r))..ctor(num12 + 5f * value, num16 + 1f * value, num10 - 10f * value, num2 - 2f * value); if ((i & 1) == 1) { Fill(r, _cZebra, 6f * value); } if (player.IsLocal && Plugin.HighlightSelf.Value) { Fill(r, _cSelf, 6f * value); Fill(new Rect(num12 + 5f * value, num16 + 5f * value, 3f * value, num2 - 10f * value), _cAccent, 1.5f * value); } float num17 = num2 - 10f * value; Rect r2 = new Rect(num12 + num, num16 + 5f * value, num7, num17); var (c, color) = BadgeColors(displayRow.RankKind, displayRow.RankContent.text); Fill(r2, c, num17 * 0.35f); ShadowLabel(r2, displayRow.RankContent, _rankText, color); ShadowLabel(new Rect(num14, num16, num15 - _scoreColumnWidth - num4 - num14, num2), displayRow.NameContent, _name); GUI.Label(new Rect(num15 - _scoreColumnWidth, num16, _scoreColumnWidth, num2), displayRow.ScoreContent, player.Ranked ? _score : _muted); num16 += num2; } } private static void Fill(Rect r, Color c, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) GUI.DrawTexture(r, (Texture)(object)Texture2D.whiteTexture, (ScaleMode)0, true, 0f, c, 0f, radius); } private static void ShadowLabel(Rect r, GUIContent content, GUIStyle style) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) ShadowLabel(r, content, style, style.normal.textColor); } private static void ShadowLabel(Rect r, GUIContent content, GUIStyle style, Color color) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) Color textColor = style.normal.textColor; style.normal.textColor = new Color(0f, 0f, 0f, 0.5f); GUI.Label(new Rect(((Rect)(ref r)).x + 1f, ((Rect)(ref r)).y + 1.5f, ((Rect)(ref r)).width, ((Rect)(ref r)).height), content, style); style.normal.textColor = color; GUI.Label(r, content, style); style.normal.textColor = textColor; } private static int ParseNum(string text) { int num = 0; bool flag = false; foreach (char c in text) { if (c >= '0' && c <= '9') { num = num * 10 + (c - 48); flag = true; } else if (flag) { break; } } if (!flag) { return -1; } return num; } private static (Color bg, Color fg) BadgeColors(RankKind kind, string text) { //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0160: 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) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) return kind switch { RankKind.Top10 => ParseNum(text) switch { 1 => (bg: new Color(1f, 0.84f, 0.3f, 0.22f), fg: new Color(1f, 0.89f, 0.48f)), 2 => (bg: new Color(0.82f, 0.86f, 0.92f, 0.2f), fg: new Color(0.93f, 0.96f, 1f)), 3 => (bg: new Color(0.8f, 0.52f, 0.3f, 0.24f), fg: new Color(1f, 0.74f, 0.48f)), _ => (bg: new Color(1f, 0.84f, 0.3f, 0.14f), fg: new Color(1f, 0.86f, 0.42f)), }, RankKind.Cheater => (bg: new Color(1f, 0.3f, 0.3f, 0.2f), fg: new Color(1f, 0.47f, 0.44f)), RankKind.Normal => (bg: new Color(1f, 1f, 1f, 0.07f), fg: new Color(0.92f, 0.94f, 0.98f)), _ => (bg: new Color(1f, 1f, 1f, 0.035f), fg: new Color(0.55f, 0.58f, 0.64f)), }; } private void BuildStyles() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: 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_01c8: Expected O, but got Unknown //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Expected O, but got Unknown //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Expected O, but got Unknown //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Expected O, but got Unknown //IL_02af: Unknown result type (might be due to invalid IL or missing references) float value = Plugin.Scale.Value; if (!_stylesBuilt || !Mathf.Approximately(_stylesScale, value)) { _stylesBuilt = true; _stylesScale = value; _layoutDirty = true; int fontSize = Mathf.RoundToInt(15f * value); _cPanel = new Color(0.07f, 0.08f, 0.1f, 0.93f); _cBorder = new Color(1f, 1f, 1f, 0.1f); _cZebra = new Color(1f, 1f, 1f, 0.03f); _cSelf = new Color(0.22f, 0.55f, 0.32f, 0.22f); _cAccent = new Color(1f, 0.84f, 0.3f, 1f); _cAccentDim = new Color(1f, 0.84f, 0.3f, 0.45f); _title = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)3, fontStyle = (FontStyle)1, fontSize = fontSize }; _title.normal.textColor = new Color(0.97f, 0.95f, 0.86f); _count = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)5, fontSize = Mathf.RoundToInt(12f * value) }; _count.normal.textColor = new Color(0.62f, 0.66f, 0.72f); _rankText = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontStyle = (FontStyle)1, fontSize = fontSize }; _rankText.normal.textColor = Color.white; _name = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)3, fontSize = fontSize, clipping = (TextClipping)1 }; _name.normal.textColor = new Color(0.94f, 0.95f, 0.97f); _score = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)5, fontSize = Mathf.RoundToInt(13f * value) }; _score.normal.textColor = new Color(0.8f, 0.84f, 0.9f); _muted = new GUIStyle(_score) { fontStyle = (FontStyle)2 }; _muted.normal.textColor = new Color(0.5f, 0.53f, 0.59f); } } } }