using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
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;
[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.0.1")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Log;
internal static ConfigEntry<bool> Enabled;
internal static ConfigEntry<bool> ShowScore;
internal static ConfigEntry<bool> HighlightSelf;
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;
private void Awake()
{
//IL_0085: 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_00d1: Expected O, but got Unknown
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Expected O, but got Unknown
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_014b: Expected O, but got Unknown
//IL_0179: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_0184: Expected O, but got Unknown
//IL_0184: 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.");
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 auto-detect the game's leaderboard from its Heathen LeaderboardObject. Only set this if auto-detection fails - the detected name is logged once at startup.");
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 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 bool _requestInFlight;
private static float _lastRequestAt = -999f;
private const float MinRequestInterval = 4f;
internal static bool BoardReady => _state == State.Ready;
internal static bool BoardFailed => _state == State.Failed;
internal static string ApiName => _apiName;
internal static void EnsureBoard(float now)
{
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: 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))
{
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.Idle;
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_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: 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)
if (ioFailure || result.m_bLeaderboardFound == 0)
{
_state = State.Failed;
Plugin.Log.LogWarning((object)$"[LobbyRanks] Leaderboard '{_apiName}' not found (ioFailure={ioFailure}).");
}
else
{
_board = result.m_hSteamLeaderboard;
_state = State.Ready;
Plugin.Log.LogInfo((object)("[LobbyRanks] Leaderboard '" + _apiName + "' resolved."));
}
}
internal static void Refresh(IReadOnlyList<ulong> roster, float now)
{
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
if (_state != State.Ready || _requestInFlight || roster.Count == 0)
{
return;
}
HashSet<ulong> hashSet = new HashSet<ulong>(roster);
if ((hashSet.SetEquals(_lastRequested) && now - _lastRequestAt < 30f) || now - _lastRequestAt < 4f)
{
return;
}
try
{
if (_downloadCall == null)
{
_downloadCall = CallResult<LeaderboardScoresDownloaded_t>.Create((APIDispatchDelegate<LeaderboardScoresDownloaded_t>)OnDownload);
}
CSteamID[] array = ((IEnumerable<ulong>)roster).Select((Func<ulong, CSteamID>)((ulong id) => new CSteamID(id))).ToArray();
SteamAPICall_t val = SteamUserStats.DownloadLeaderboardEntriesForUsers(_board, array, array.Length);
_downloadCall.Set(val, (APIDispatchDelegate<LeaderboardScoresDownloaded_t>)null);
_requestInFlight = true;
_lastRequested = hashSet;
_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_008d: 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_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: 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_006e: 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;
}
HashSet<ulong> hashSet = new HashSet<ulong>();
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;
hashSet.Add(steamID);
_cache[steamID] = new PlayerRow
{
SteamId = steamID,
Rank = val.m_nGlobalRank,
Score = val.m_nScore,
Ranked = true
};
}
}
foreach (ulong item in _lastRequested)
{
if (!hashSet.Contains(item))
{
_cache[item] = new PlayerRow
{
SteamId = item,
Rank = 0,
Score = 0,
Ranked = false
};
}
}
}
internal static bool TryGet(ulong id, out PlayerRow row)
{
return _cache.TryGetValue(id, out row);
}
private static string ResolveApiName()
{
string value = Plugin.ApiNameOverride.Value;
if (!string.IsNullOrEmpty(value))
{
return value;
}
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 text && !string.IsNullOrEmpty(text))
{
return text;
}
}
return null;
}
}
internal class LobbyRanksBehaviour : MonoBehaviour
{
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 readonly List<PlayerRow> _roster = new List<PlayerRow>();
private bool _stylesBuilt;
private GUIStyle _title;
private GUIStyle _rank;
private GUIStyle _name;
private GUIStyle _score;
private GUIStyle _muted;
private Texture2D _bgTex;
private Texture2D _selfTex;
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)
{
return;
}
_nextRosterPoll = Time.unscaledTime + 1f;
if (!Ranks.BoardReady)
{
Ranks.EnsureBoard(Time.unscaledTime);
}
PollRoster();
if (_roster.Count > 0)
{
Ranks.Refresh(_roster.Select((PlayerRow r) => r.SteamId).ToList(), Time.unscaledTime);
}
}
private void PollRoster()
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
_roster.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);
}
}
}
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 OnGUI()
{
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_021c: Unknown result type (might be due to invalid IL or missing references)
//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
//IL_026b: Unknown result type (might be due to invalid IL or missing references)
//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
if (!Plugin.Enabled.Value || _hidden || _roster.Count == 0)
{
return;
}
BuildStyles();
float value = Plugin.Scale.Value;
float num = 26f * value;
float num2 = 10f * value;
float num3 = 26f * value;
float num4 = 300f * value;
List<PlayerRow> list = (from r in _roster
orderby (!r.Ranked) ? 1 : 0, (!r.Ranked) ? int.MaxValue : r.Rank
select r).ToList();
float num5 = num3 + num2 + (float)list.Count * num + num2;
float num6 = Mathf.Clamp(Plugin.PanelX.Value * (float)Screen.width - num4 / 2f, 0f, (float)Screen.width - num4);
float num7 = Plugin.PanelY.Value * (float)Screen.height;
GUI.DrawTexture(new Rect(num6, num7, num4, num5), (Texture)(object)_bgTex);
GUI.Label(new Rect(num6, num7 + 4f * value, num4, num3), "LOBBY RANKS", _title);
float num8 = num7 + num3 + num2 * 0.5f;
Rect val = default(Rect);
foreach (PlayerRow item in list)
{
((Rect)(ref val))..ctor(num6, num8, num4, num);
if (item.IsLocal && Plugin.HighlightSelf.Value)
{
GUI.DrawTexture(val, (Texture)(object)_selfTex);
}
float num9 = num6 + 12f * value;
if (item.Ranked && item.Rank > 0)
{
Rect val2 = new Rect(num9, num8, 70f * value, num);
int rank = item.Rank;
GUI.Label(val2, "#" + rank, _rank);
}
else if (Ranks.BoardReady)
{
GUI.Label(new Rect(num9, num8, 70f * value, num), "—", _muted);
}
else
{
GUI.Label(new Rect(num9, num8, 70f * value, num), "…", _muted);
}
string text = item.Name + (item.IsLocal ? " (you)" : "");
GUI.Label(new Rect(num9 + 74f * value, num8, num4 - 150f * value, num), text, _name);
string text2;
if (item.Ranked)
{
object obj;
if (!Plugin.ShowScore.Value)
{
obj = "";
}
else
{
int rank = item.Score;
obj = rank.ToString("N0");
}
text2 = (string)obj;
}
else
{
text2 = ((!Ranks.BoardReady) ? "" : "unranked");
}
GUI.Label(new Rect(num6, num8, num4 - 12f * value, num), text2, _score);
num8 += num;
}
}
private void BuildStyles()
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Expected O, but got Unknown
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Expected O, but got Unknown
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: 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_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Expected O, but got Unknown
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_018d: Expected O, but got Unknown
//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
//IL_01c2: Expected O, but got Unknown
//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
if (!_stylesBuilt)
{
_stylesBuilt = true;
_bgTex = SolidTex(new Color(0.05f, 0.06f, 0.08f, 0.86f));
_selfTex = SolidTex(new Color(0.2f, 0.55f, 0.3f, 0.3f));
int fontSize = Mathf.RoundToInt(16f * Plugin.Scale.Value);
_title = new GUIStyle(GUI.skin.label)
{
alignment = (TextAnchor)4,
fontStyle = (FontStyle)1,
fontSize = Mathf.RoundToInt(15f * Plugin.Scale.Value)
};
_title.normal.textColor = new Color(0.96f, 0.93f, 0.82f);
_rank = new GUIStyle(GUI.skin.label)
{
alignment = (TextAnchor)3,
fontStyle = (FontStyle)1,
fontSize = fontSize
};
_rank.normal.textColor = new Color(1f, 0.84f, 0.3f);
_name = new GUIStyle(GUI.skin.label)
{
alignment = (TextAnchor)3,
fontSize = fontSize
};
_name.normal.textColor = Color.white;
_score = new GUIStyle(GUI.skin.label)
{
alignment = (TextAnchor)5,
fontSize = Mathf.RoundToInt(14f * Plugin.Scale.Value)
};
_score.normal.textColor = new Color(0.78f, 0.82f, 0.88f);
_muted = new GUIStyle(_rank);
_muted.normal.textColor = new Color(0.55f, 0.58f, 0.62f);
}
}
private static Texture2D SolidTex(Color c)
{
//IL_0002: 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_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Expected O, but got Unknown
Texture2D val = new Texture2D(1, 1);
val.SetPixel(0, 0, c);
val.Apply();
((Object)val).hideFlags = (HideFlags)61;
return val;
}
}
}