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<bool> Enabled;
internal static ConfigEntry<bool> ShowScore;
internal static ConfigEntry<bool> HighlightSelf;
internal static ConfigEntry<bool> CheaterAdjusted;
internal static ConfigEntry<float> PanelX;
internal static ConfigEntry<float> PanelY;
internal static ConfigEntry<float> Scale;
internal static ConfigEntry<KeyboardShortcut> ToggleKey;
internal static ConfigEntry<string> ApiNameOverride;
internal static ConfigEntry<string> 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<bool>("LobbyRanks.Display", "Enabled", true, "Master toggle for the lobby rank panel.");
ShowScore = ((BaseUnityPlugin)this).Config.Bind<bool>("LobbyRanks.Display", "ShowScore", true, "Show each player's raw leaderboard score (gamesWon*4 + roundsWon) beside their global rank.");
HighlightSelf = ((BaseUnityPlugin)this).Config.Bind<bool>("LobbyRanks.Display", "HighlightYou", true, "Tint your own row so you can spot it at a glance.");
CheaterAdjusted = ((BaseUnityPlugin)this).Config.Bind<bool>("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<KeyboardShortcut>("LobbyRanks.Display", "ToggleKey", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Hotkey to show/hide the panel.");
PanelX = ((BaseUnityPlugin)this).Config.Bind<float>("LobbyRanks.Panel", "CenterX", 0.5f, new ConfigDescription("Panel horizontal center as a fraction of screen width.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
PanelY = ((BaseUnityPlugin)this).Config.Bind<float>("LobbyRanks.Panel", "TopY", 0.1f, new ConfigDescription("Panel top edge as a fraction of screen height.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.9f), Array.Empty<object>()));
Scale = ((BaseUnityPlugin)this).Config.Bind<float>("LobbyRanks.Panel", "Scale", 1f, new ConfigDescription("Panel scale.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.6f, 2f), Array.Empty<object>()));
ApiNameOverride = ((BaseUnityPlugin)this).Config.Bind<string>("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<string>("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<LobbyRanksBehaviour>();
((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<LeaderboardFindResult_t> _findCall;
private static CallResult<LeaderboardScoresDownloaded_t> _downloadCall;
private static readonly Dictionary<ulong, PlayerRow> _cache = new Dictionary<ulong, PlayerRow>();
private static HashSet<ulong> _lastRequested = new HashSet<ulong>();
private static readonly HashSet<ulong> _requestScratch = new HashSet<ulong>();
private static readonly HashSet<ulong> _downloadedScratch = new HashSet<ulong>();
private static readonly List<ulong> _pruneKeys = new List<ulong>();
private static bool _requestInFlight;
private static float _lastRequestAt = -999f;
private static int _dataVersion;
private const float MinRequestInterval = 4f;
private static readonly Dictionary<ulong, int> _top10Rank = new Dictionary<ulong, int>();
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<LeaderboardFindResult_t>.Create((APIDispatchDelegate<LeaderboardFindResult_t>)OnFind);
}
_apiName = text;
_state = State.Finding;
_retryAt = now + 15f;
SteamAPICall_t val = SteamUserStats.FindLeaderboard(text);
_findCall.Set(val, (APIDispatchDelegate<LeaderboardFindResult_t>)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<ulong> 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<LeaderboardScoresDownloaded_t>.Create((APIDispatchDelegate<LeaderboardScoresDownloaded_t>)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<LeaderboardScoresDownloaded_t>)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<ulong, int> top10, int offset)
{
_top10Rank.Clear();
foreach (KeyValuePair<ulong, int> 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<PlayerRow> _roster = new List<PlayerRow>();
private readonly List<ulong> _steamIds = new List<ulong>();
private readonly List<PlayerRow> _sortedRoster = new List<PlayerRow>();
private readonly List<DisplayRow> _displayRows = new List<DisplayRow>();
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<ulong> hashSet = new HashSet<ulong>();
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<ulong, int> ranks = new Dictionary<ulong, int>();
CallResult<LeaderboardScoresDownloaded_t> call = CallResult<LeaderboardScoresDownloaded_t>.Create((APIDispatchDelegate<LeaderboardScoresDownloaded_t>)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<LeaderboardScoresDownloaded_t>)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<bool>)(() => done));
}
if (ranks.Count == 0)
{
Plugin.Log.LogWarning((object)"[LobbyRanks] No whitelisted players were ranked; showing raw ranks.");
yield break;
}
List<KeyValuePair<ulong, int>> list = new List<KeyValuePair<ulong, int>>(ranks);
list.Sort((KeyValuePair<ulong, int> left, KeyValuePair<ulong, int> right) => left.Value.CompareTo(right.Value));
if (list.Count > 10)
{
list.RemoveRange(10, list.Count - 10);
}
Dictionary<ulong, int> dictionary = new Dictionary<ulong, int>();
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);
}
}
}
}