Decompiled source of BoplPlayerHistory v1.5.0

BoplPlayerHistory.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using Steamworks;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BoplPlayerHistory")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BoplPlayerHistory")]
[assembly: AssemblyTitle("BoplPlayerHistory")]
[assembly: AssemblyVersion("1.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;
		}
	}
}
[Serializable]
public sealed class PlayerDatabase
{
	public List<PlayerRecord> players = new List<PlayerRecord>();
}
[Serializable]
public sealed class PlayerRecord
{
	public string steamId;

	public string nickname;

	public long lastMetUnixSeconds;
}
[BepInPlugin("com.creed.bopl.playerhistory", "Bopl Player History", "1.3.1-DEBUG")]
public sealed class BoplPlayerHistoryPlugin : BaseUnityPlugin
{
	private const float ScanInterval = 2f;

	private const float SaveInterval = 15f;

	private const int MinimumRememberedPlayers = 1;

	private const int MaximumRememberedPlayers = 1000;

	private const int WindowId = 741205;

	private const float MinWindowWidth = 380f;

	private const float MinWindowHeight = 280f;

	private const float ResizeHandleSize = 20f;

	private readonly PlayerDatabase _database = new PlayerDatabase();

	private readonly Dictionary<string, string> _lastMetSnapshot = new Dictionary<string, string>();

	private ConfigEntry<int> _rememberLimit;

	private ConfigEntry<bool> _openOnStartup;

	private GUIStyle _creditStyle;

	private float _nextScan;

	private float _nextSave;

	private bool _dirty;

	private bool _isOpen;

	private bool _confirmClear;

	private bool _isResizing;

	private Vector2 _resizeStartMouse;

	private Vector2 _resizeStartSize;

	private Rect _windowRect;

	private string _expandedSteamId = string.Empty;

	private string _searchQuery = string.Empty;

	private bool _sortByName;

	private Vector2 _scrollPosition;

	private int _creditClicks;

	private string _easterEggMessage = "Made By UxCreed";

	private string DatabasePath => Path.Combine(Application.persistentDataPath, "BoplPlayerHistory", "players.txt");

	private void Awake()
	{
		//IL_0104: 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_011a: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEBUG] Awake() started.");
			_rememberLimit = ((BaseUnityPlugin)this).Config.Bind<int>("History", "RememberedPlayers", 100, "Max players.");
			_rememberLimit.Value = Mathf.Clamp(_rememberLimit.Value, 1, 1000);
			_openOnStartup = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "OpenOnStartup", true, "Open on start.");
			LoadDatabase();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[DEBUG] Awake() screen size: {Screen.width}x{Screen.height}");
			float num = Mathf.Min(620f, (float)Screen.width - 40f);
			float num2 = Mathf.Min(520f, (float)Screen.height - 40f);
			_windowRect = new Rect(Mathf.Max(0f, ((float)Screen.width - num) * 0.5f), Mathf.Max(0f, ((float)Screen.height - num2) * 0.5f), num, num2);
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[DEBUG] Awake() initialized window rect: {_windowRect}");
			if (_openOnStartup.Value)
			{
				OpenHistoryWindow();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEBUG] Awake() finished successfully.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[DEBUG] CRASH IN AWAKE: " + ex.ToString()));
		}
	}

	private void Start()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEBUG] Start() called.");
		try
		{
			CharacterSelectHandler_online.clientSideMods_you_can_increment_this_to_enable_matchmaking_for_your_mods__please_dont_use_it_to_cheat_thats_really_cringe_especially_if_its_desyncing_others___you_didnt_even_win_on_your_opponents_screen___I_cannot_imagine_a_sadder_existence++;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[DEBUG] CRASH IN START: " + ex.ToString()));
		}
	}

	private void Update()
	{
		try
		{
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime >= _nextScan)
			{
				_nextScan = unscaledTime + 2f;
				ObserveConnectedPlayers();
			}
			if (_dirty && unscaledTime >= _nextSave)
			{
				SaveDatabase();
				_nextSave = unscaledTime + 15f;
			}
			HandleResize();
			if (Keyboard.current == null)
			{
				return;
			}
			if (((ButtonControl)Keyboard.current.hKey).wasPressedThisFrame)
			{
				bool flag = ((ButtonControl)Keyboard.current.leftShiftKey).isPressed || ((ButtonControl)Keyboard.current.rightShiftKey).isPressed;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[DEBUG] 'H' key pressed. Shift held: {flag}");
				if (flag)
				{
					if (_isOpen)
					{
						_isOpen = false;
						((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEBUG] Closed window via Shift+H");
					}
					else
					{
						OpenHistoryWindow();
					}
				}
			}
			if (_isOpen && ((ButtonControl)Keyboard.current.escapeKey).wasPressedThisFrame)
			{
				_isOpen = false;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEBUG] Closed window via Escape");
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[DEBUG] CRASH IN UPDATE: " + ex.ToString()));
		}
	}

	private void HandleResize()
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: 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_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		if (_isOpen && Mouse.current != null)
		{
			Vector2 val = ((InputControl<Vector2>)(object)((Pointer)Mouse.current).position).ReadValue();
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(val.x, (float)Screen.height - val.y);
			Rect val3 = default(Rect);
			((Rect)(ref val3))..ctor(((Rect)(ref _windowRect)).x + ((Rect)(ref _windowRect)).width - 20f, ((Rect)(ref _windowRect)).y + ((Rect)(ref _windowRect)).height - 20f, 20f, 20f);
			if (Mouse.current.leftButton.wasPressedThisFrame && ((Rect)(ref val3)).Contains(val2))
			{
				_isResizing = true;
				_resizeStartMouse = val2;
				_resizeStartSize = new Vector2(((Rect)(ref _windowRect)).width, ((Rect)(ref _windowRect)).height);
			}
			else if (_isResizing && Mouse.current.leftButton.isPressed)
			{
				Vector2 val4 = val2 - _resizeStartMouse;
				((Rect)(ref _windowRect)).width = Mathf.Max(380f, _resizeStartSize.x + val4.x);
				((Rect)(ref _windowRect)).height = Mathf.Max(280f, _resizeStartSize.y + val4.y);
			}
			else if (_isResizing && Mouse.current.leftButton.wasReleasedThisFrame)
			{
				_isResizing = false;
			}
		}
	}

	private void OnGUI()
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Invalid comparison between Unknown and I4
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Expected O, but got Unknown
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if ((int)Event.current.type == 8)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[DEBUG] OnGUI running. Screen: {Screen.width}x{Screen.height}. IsOpen: {_isOpen}. WindowRect: {_windowRect}");
			}
			MainMenu val = Object.FindObjectOfType<MainMenu>();
			if (!_isOpen && (Object)(object)val != (Object)null && ((Behaviour)val).isActiveAndEnabled && val.IsEnabled && GUI.Button(new Rect((float)Screen.width - 132f, 18f, 112f, 42f), "History"))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEBUG] Clicked History button in Main Menu.");
				OpenHistoryWindow();
			}
			if (_isOpen)
			{
				_windowRect = GUI.Window(741205, _windowRect, new WindowFunction(DrawWindow), "Players You Met");
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[DEBUG] CRASH IN ONGUI: " + ex.ToString()));
		}
	}

	private void DrawWindow(int windowId)
	{
		//IL_0265: Unknown result type (might be due to invalid IL or missing references)
		//IL_0279: Unknown result type (might be due to invalid IL or missing references)
		//IL_027e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d7: Expected O, but got Unknown
		//IL_037f: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
		GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label("Saved locally. Last-met age refreshes on open.", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
		{
			_isOpen = false;
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (_confirmClear)
		{
			GUILayout.Label("Clear all players?", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			if (GUILayout.Button("Confirm", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
			{
				ClearRecentPlayers();
			}
			if (GUILayout.Button("Cancel", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
			{
				_confirmClear = false;
			}
		}
		else if (GUILayout.Button("Clear all players?", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }))
		{
			_confirmClear = true;
		}
		GUILayout.Label("Limit: " + _rememberLimit.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
		if (GUILayout.Button("-", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(30f) }))
		{
			SetRememberLimit(_rememberLimit.Value - 10);
		}
		if (GUILayout.Button("+", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(30f) }))
		{
			SetRememberLimit(_rememberLimit.Value + 10);
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label("Search:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
		_searchQuery = GUILayout.TextField(_searchQuery ?? string.Empty, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		if (GUILayout.Button(_sortByName ? "Sort: Name" : "Sort: Recent", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
		{
			_sortByName = !_sortByName;
		}
		GUILayout.EndHorizontal();
		GUILayout.Label("Players (" + _database.players.Count + ")", GUI.skin.box, Array.Empty<GUILayoutOption>());
		_scrollPosition = GUILayout.BeginScrollView(_scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
		DrawPlayerList();
		GUILayout.EndScrollView();
		if (_creditStyle == null)
		{
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 10
			};
			val.normal.textColor = new Color(1f, 1f, 1f, 0.55f);
			_creditStyle = val;
		}
		if (GUILayout.Button(_easterEggMessage, _creditStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(20f) }))
		{
			_creditClicks++;
			if (_creditClicks == 3)
			{
				_easterEggMessage = "Made By UxCreed & The Copilot \ud83d\udc10";
			}
			if (_creditClicks >= 5)
			{
				_easterEggMessage = "You found the secret! \ud83e\udd5a (Click to reset)";
			}
			if (_creditClicks > 6)
			{
				_creditClicks = 0;
				_easterEggMessage = "Made By UxCreed";
			}
		}
		GUILayout.EndVertical();
		GUI.Box(new Rect(((Rect)(ref _windowRect)).width - 20f, ((Rect)(ref _windowRect)).height - 20f, 20f, 20f), "◢");
		GUI.DragWindow(new Rect(0f, 0f, 10000f, 24f));
	}

	private void DrawPlayerList()
	{
		List<PlayerRecord> source = _database.players.Where((PlayerRecord r) => r != null && (string.IsNullOrWhiteSpace(_searchQuery) || r.nickname.IndexOf(_searchQuery, StringComparison.OrdinalIgnoreCase) >= 0 || r.steamId.Contains(_searchQuery))).ToList();
		source = ((!_sortByName) ? source.OrderByDescending((PlayerRecord r) => r.lastMetUnixSeconds).ToList() : source.OrderBy((PlayerRecord r) => r.nickname).ToList());
		if (source.Count == 0)
		{
			GUILayout.Label(string.IsNullOrEmpty(_searchQuery) ? "No players remembered yet." : "No players match your search.", Array.Empty<GUILayoutOption>());
			return;
		}
		PlayerRecord playerRecord = null;
		foreach (PlayerRecord item in source)
		{
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			if (GUILayout.Button((string.IsNullOrWhiteSpace(item.nickname) ? "Unknown player" : item.nickname) + ((item.steamId == _expandedSteamId) ? "  -" : "  +"), Array.Empty<GUILayoutOption>()))
			{
				_expandedSteamId = ((item.steamId == _expandedSteamId) ? string.Empty : item.steamId);
			}
			if (item.steamId == _expandedSteamId)
			{
				if (!_lastMetSnapshot.TryGetValue(item.steamId, out var value))
				{
					value = FormatLastMetAge(item.lastMetUnixSeconds);
					_lastMetSnapshot[item.steamId] = value;
				}
				GUILayout.Label("Last met: " + value, Array.Empty<GUILayoutOption>());
				GUILayout.Label("Steam ID: " + item.steamId, Array.Empty<GUILayoutOption>());
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("Profile", Array.Empty<GUILayoutOption>()))
				{
					OpenSteamProfile(item.steamId);
				}
				if (GUILayout.Button("Copy ID", Array.Empty<GUILayoutOption>()))
				{
					GUIUtility.systemCopyBuffer = item.steamId;
				}
				if (GUILayout.Button("Delete", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
				{
					playerRecord = item;
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.EndVertical();
		}
		if (playerRecord != null)
		{
			_database.players.Remove(playerRecord);
			_lastMetSnapshot.Remove(playerRecord.steamId);
			MarkDirty();
		}
	}

	private void OpenHistoryWindow()
	{
		_isOpen = true;
		((BaseUnityPlugin)this).Logger.LogInfo((object)"[DEBUG] OpenHistoryWindow() called. _isOpen set to true.");
		RefreshLastMetSnapshot();
	}

	private void ObserveConnectedPlayers()
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		SteamManager instance = SteamManager.instance;
		if ((Object)(object)instance == (Object)null || instance.connectedPlayers == null)
		{
			return;
		}
		long num = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
		bool flag = false;
		for (int i = 0; i < instance.connectedPlayers.Count; i++)
		{
			SteamConnection val = instance.connectedPlayers[i];
			if (val == null || !((ConnectionManager)val).Connected)
			{
				continue;
			}
			ulong num2 = SteamId.op_Implicit(val.id);
			if (num2 == 0L)
			{
				continue;
			}
			string text = num2.ToString(CultureInfo.InvariantCulture);
			PlayerRecord playerRecord = FindPlayer(text);
			if (playerRecord == null)
			{
				playerRecord = new PlayerRecord
				{
					steamId = text,
					nickname = NormalizeNickname(val.steamName, text),
					lastMetUnixSeconds = num
				};
				_database.players.Add(playerRecord);
				TrimRecentPlayers();
				MarkDirty();
				flag = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[DEBUG] Added new player: " + playerRecord.nickname + " (" + text + ")"));
			}
			else
			{
				bool flag2 = false;
				string text2 = NormalizeNickname(val.steamName, text);
				if (!string.Equals(playerRecord.nickname, text2, StringComparison.Ordinal))
				{
					playerRecord.nickname = text2;
					flag2 = true;
				}
				if (num - playerRecord.lastMetUnixSeconds >= 10)
				{
					playerRecord.lastMetUnixSeconds = num;
					flag2 = true;
				}
				if (flag2)
				{
					MarkDirty();
				}
			}
		}
		if (flag)
		{
			SaveDatabase();
		}
	}

	private void LoadDatabase()
	{
		try
		{
			if (!File.Exists(DatabasePath))
			{
				return;
			}
			string[] array = File.ReadAllLines(DatabasePath);
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (!string.IsNullOrWhiteSpace(text))
				{
					string[] array3 = text.Split('|');
					if (array3.Length >= 3 && ulong.TryParse(array3[0], NumberStyles.None, CultureInfo.InvariantCulture, out var result) && result != 0L && hashSet.Add(array3[0]))
					{
						_database.players.Add(new PlayerRecord
						{
							steamId = array3[0],
							nickname = array3[1],
							lastMetUnixSeconds = long.Parse(array3[2])
						});
					}
				}
			}
			TrimRecentPlayers();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[PlayerHistory] loaded " + _database.players.Count + " saved player record(s)."));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[DEBUG] failed to load player history: " + ex));
		}
	}

	private bool SaveDatabase()
	{
		try
		{
			string directoryName = Path.GetDirectoryName(DatabasePath);
			if (string.IsNullOrEmpty(directoryName))
			{
				return false;
			}
			Directory.CreateDirectory(directoryName);
			List<string> list = new List<string>();
			foreach (PlayerRecord player in _database.players)
			{
				string arg = (player.nickname ?? "").Replace("|", "");
				list.Add($"{player.steamId}|{arg}|{player.lastMetUnixSeconds}");
			}
			string text = DatabasePath + ".tmp";
			File.WriteAllLines(text, list);
			if (File.Exists(DatabasePath))
			{
				File.Delete(DatabasePath);
			}
			File.Move(text, DatabasePath);
			_dirty = false;
			return true;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[DEBUG] failed to save player history: " + ex));
			return false;
		}
	}

	private void OnApplicationQuit()
	{
		if (_dirty)
		{
			SaveDatabase();
		}
	}

	private void OnDestroy()
	{
		if (_dirty)
		{
			SaveDatabase();
		}
	}

	private void RefreshLastMetSnapshot()
	{
		_lastMetSnapshot.Clear();
		foreach (PlayerRecord player in _database.players)
		{
			if (player != null)
			{
				_lastMetSnapshot[player.steamId] = FormatLastMetAge(player.lastMetUnixSeconds);
			}
		}
	}

	private static string FormatLastMetAge(long timestamp)
	{
		if (timestamp <= 0)
		{
			return "Unknown";
		}
		long num = Math.Max(0L, DateTimeOffset.UtcNow.ToUnixTimeSeconds() - timestamp);
		if (num < 60)
		{
			return "Just now";
		}
		if (num < 3600)
		{
			return num / 60 + " minute(s) ago";
		}
		if (num < 86400)
		{
			return num / 3600 + " hour(s) ago";
		}
		return num / 86400 + " day(s) ago";
	}

	private static string NormalizeNickname(string nickname, string fallback)
	{
		if (!string.IsNullOrWhiteSpace(nickname))
		{
			return nickname.Trim();
		}
		return "Player " + fallback;
	}

	private PlayerRecord FindPlayer(string steamId)
	{
		return _database.players.FirstOrDefault((PlayerRecord r) => r != null && string.Equals(r.steamId, steamId, StringComparison.Ordinal));
	}

	private void SetRememberLimit(int value)
	{
		_rememberLimit.Value = Mathf.Clamp(value, 1, 1000);
		((BaseUnityPlugin)this).Config.Save();
		TrimRecentPlayers();
		MarkDirty();
	}

	private void TrimRecentPlayers()
	{
		while (_database.players.Count > _rememberLimit.Value)
		{
			PlayerRecord playerRecord = _database.players.OrderBy((PlayerRecord r) => r.lastMetUnixSeconds).FirstOrDefault();
			if (playerRecord == null)
			{
				break;
			}
			_database.players.Remove(playerRecord);
			_lastMetSnapshot.Remove(playerRecord.steamId);
			_dirty = true;
		}
	}

	private void ClearRecentPlayers()
	{
		_database.players.Clear();
		_expandedSteamId = string.Empty;
		_confirmClear = false;
		MarkDirty();
		SaveDatabase();
	}

	private void MarkDirty()
	{
		_dirty = true;
		if (_nextSave <= Time.unscaledTime)
		{
			_nextSave = Time.unscaledTime + 15f;
		}
	}

	private void OpenSteamProfile(string steamId)
	{
		if (!ulong.TryParse(steamId, out var result) || result == 0L)
		{
			return;
		}
		try
		{
			Application.OpenURL("steam://url/SteamIDPage/" + result.ToString(CultureInfo.InvariantCulture));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Failed to open Steam profile: " + ex.Message));
		}
	}
}