Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of REPOContacts v1.1.0
REPOContacts.dll
Decompiled 18 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ClassLibrary1")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ClassLibrary1")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("47cf1faa-03e5-4dc1-abb6-d597599585b7")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace REPOContacts; public static class PluginInfo { public const string PLUGIN_GUID = "com.axiom.repocontacts"; public const string PLUGIN_NAME = "R.E.P.O. Contacts"; public const string PLUGIN_VERSION = "1.1.0"; public const string AUTHOR = "3udah"; public const string DISCORD = "75b"; } [Serializable] public class PlayerRecord { public string SteamId; public string NickName; public string FirstSeen; public string LastSeen; public int SessionsTogether; public int TotalSecondsPlayed; public bool IsFavorite; public string Notes; } [Serializable] public class SessionRecord { public string SessionId; public string Date; public string LevelName; public int LevelReached; public int TotalValue; public bool RunSucceeded; public int DurationSeconds; public string PlayerSteamIdsCombined; } [Serializable] public class ContactsDatabase { public List<PlayerRecord> Players = new List<PlayerRecord>(); public List<SessionRecord> Sessions = new List<SessionRecord>(); } [BepInPlugin("com.axiom.repocontacts", "R.E.P.O. Contacts", "1.1.0")] public class ContactsPlugin : BaseUnityPlugin { internal static ManualLogSource Logger; internal static ConfigEntry<KeyCode> ToggleKey; internal static ConfigEntry<bool> ShowJoinNotifications; private static ContactsDatabase _db = new ContactsDatabase(); private static readonly object _dbLock = new object(); private static readonly string SavePath = Path.Combine(Paths.ConfigPath, "REPOContacts"); private static readonly string SaveFile = Path.Combine(SavePath, "contacts.json"); private static SessionRecord _currentSession; private static float _sessionTimer = 0f; private static float _scanTimer = 0f; private static float _playTimeTimer = 0f; private static bool _uiVisible = false; private static string _searchQuery = ""; private static int _currentFilter = 0; private static PlayerRecord _selectedPlayer = null; private static int _playerDetailTab = 0; private static SessionRecord _selectedSession = null; private static Vector2 _mainScroll = Vector2.zero; private static Vector2 _detailScroll = Vector2.zero; private static Vector2 _sessionScroll = Vector2.zero; private static string _notesEditText = ""; private static bool _editingNotes = false; private static string _notificationText = ""; private static float _notificationTimer = 0f; private static float _notificationDuration = 5f; private static Type _runManagerType; private static Type _playerAvatarType; private static bool _typesResolved = false; private static HashSet<string> _currentlyOnline = new HashSet<string>(); private static Dictionary<string, float> _playerPlayTime = new Dictionary<string, float>(); private static Rect _windowRect = new Rect(20f, 20f, 520f, 600f); private static Texture2D _modernBg; private static Texture2D _modernHeader; private static Texture2D _modernBtn; private static Texture2D _modernBtnHover; private void Awake() { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) Logger = ((BaseUnityPlugin)this).Logger; ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ToggleKey", (KeyCode)291, "Key to toggle the Contacts overlay"); ShowJoinNotifications = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowJoinNotifications", true, "Show notification when someone you know joins"); ((BaseUnityPlugin)this).Config.Bind<string>("Credits", "Author", "3udah", "Mod author (read-only)"); ((BaseUnityPlugin)this).Config.Bind<string>("Credits", "Discord", "75b", "Author Discord (read-only)"); Directory.CreateDirectory(SavePath); LoadDatabase(); ResolveTypes(); Logger.LogInfo((object)$"R.E.P.O. Contacts loaded! Press {ToggleKey.Value} to open. Fuck yeah."); Harmony.CreateAndPatchAll(typeof(ContactsPlugin), (string)null); } private void ResolveTypes() { _runManagerType = AccessTools.TypeByName("RunManager"); _playerAvatarType = AccessTools.TypeByName("PlayerAvatar"); _typesResolved = _runManagerType != null && _playerAvatarType != null; Logger.LogInfo((object)$"Type resolution: RunManager={_runManagerType != null}, PlayerAvatar={_playerAvatarType != null}"); } private void Update() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(ToggleKey.Value)) { _uiVisible = !_uiVisible; if (_uiVisible && _selectedPlayer != null) { _notesEditText = _selectedPlayer.Notes ?? ""; } } _scanTimer -= Time.deltaTime; if (_scanTimer <= 0f) { _scanTimer = 5f; ScanLobby(); } _playTimeTimer -= Time.deltaTime; if (_playTimeTimer <= 0f) { _playTimeTimer = 1f; UpdatePlayTime(); } if (_currentSession != null) { _sessionTimer += Time.deltaTime; _currentSession.DurationSeconds = (int)_sessionTimer; } if (_notificationTimer > 0f) { _notificationTimer -= Time.deltaTime; } } private void UpdatePlayTime() { if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom) { return; } Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val == null || val.IsLocal) { continue; } string text = val.UserId; if (string.IsNullOrEmpty(text) && _playerAvatarType != null) { try { Array array = Object.FindObjectsOfType(_playerAvatarType); FieldInfo fieldInfo = AccessTools.Field(_playerAvatarType, "steamID"); if (fieldInfo != null) { foreach (object item in array) { Component val2 = (Component)((item is Component) ? item : null); if (!((Object)(object)val2 == (Object)null)) { PhotonView component = val2.GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null && component.Owner != null && component.Owner.ActorNumber == val.ActorNumber) { text = (string)fieldInfo.GetValue(val2); break; } } } } } catch { } } if (!string.IsNullOrEmpty(text)) { if (!_playerPlayTime.ContainsKey(text)) { _playerPlayTime[text] = 0f; } _playerPlayTime[text] += 1f; } } } private void ScanLobby() { if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom) { return; } _currentlyOnline.Clear(); Dictionary<int, string> dictionary = new Dictionary<int, string>(); try { if (_playerAvatarType != null) { Array array = Object.FindObjectsOfType(_playerAvatarType); FieldInfo fieldInfo = AccessTools.Field(_playerAvatarType, "steamID"); if (fieldInfo != null) { foreach (object item in array) { Component val = (Component)((item is Component) ? item : null); if ((Object)(object)val == (Object)null) { continue; } PhotonView component = val.GetComponent<PhotonView>(); if (!((Object)(object)component == (Object)null) && component.Owner != null) { string text = (string)fieldInfo.GetValue(val); if (!string.IsNullOrEmpty(text) && text != "0") { dictionary[component.Owner.ActorNumber] = text; } } } } } } catch { } Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val2 in playerList) { if (val2 == null) { continue; } string steamId = val2.UserId; string text2 = (string.IsNullOrEmpty(val2.NickName) ? "Unknown" : val2.NickName); if (string.IsNullOrEmpty(steamId) && dictionary.ContainsKey(val2.ActorNumber)) { steamId = dictionary[val2.ActorNumber]; } if (string.IsNullOrEmpty(steamId) || steamId == "0") { steamId = "Actor_" + val2.ActorNumber; } _currentlyOnline.Add(steamId); if (val2.IsLocal) { continue; } lock (_dbLock) { PlayerRecord playerRecord = _db.Players.Find((PlayerRecord p) => p.SteamId == steamId); if (playerRecord == null) { playerRecord = new PlayerRecord { SteamId = steamId, NickName = text2, FirstSeen = DateTime.Now.ToString("yyyy-MM-dd HH:mm"), SessionsTogether = 0 }; _db.Players.Insert(0, playerRecord); } else if (ShowJoinNotifications.Value && playerRecord.SessionsTogether > 0) { ShowNotification($"\ud83d\udc4b {text2} joined!\nPlayed together {playerRecord.SessionsTogether} times"); } playerRecord.NickName = text2; playerRecord.LastSeen = DateTime.Now.ToString("yyyy-MM-dd HH:mm"); if (_currentSession != null && !_currentSession.PlayerSteamIdsCombined.Contains(steamId)) { SessionRecord currentSession = _currentSession; currentSession.PlayerSteamIdsCombined = currentSession.PlayerSteamIdsCombined + steamId + ","; } if (_playerPlayTime.ContainsKey(steamId)) { int num = (int)_playerPlayTime[steamId]; if (playerRecord.TotalSecondsPlayed < num) { playerRecord.TotalSecondsPlayed = num; } } SaveDatabase(); } } } private void ShowNotification(string text) { _notificationText = text; _notificationTimer = _notificationDuration; } [HarmonyPatch] [HarmonyPatch(typeof(RunManager), "UpdateLevel")] private static void StartSessionPostfix() { try { if (_currentSession == null && PhotonNetwork.IsConnected && PhotonNetwork.InRoom) { StartNewSession("Unknown Level"); } } catch { } } private static void StartNewSession(string levelName) { _currentSession = new SessionRecord { SessionId = Guid.NewGuid().ToString(), Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm"), LevelName = levelName, LevelReached = 1, TotalValue = 0, RunSucceeded = false, DurationSeconds = 0, PlayerSteamIdsCombined = "" }; _sessionTimer = 0f; if (PhotonNetwork.IsConnected && PhotonNetwork.InRoom) { Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val == null || val.IsLocal) { continue; } string steamId = val.UserId; if (string.IsNullOrEmpty(steamId)) { steamId = "Actor_" + val.ActorNumber; } if (!_currentSession.PlayerSteamIdsCombined.Contains(steamId)) { SessionRecord currentSession = _currentSession; currentSession.PlayerSteamIdsCombined = currentSession.PlayerSteamIdsCombined + steamId + ","; } lock (_dbLock) { PlayerRecord playerRecord = _db.Players.Find((PlayerRecord p) => p.SteamId == steamId); if (playerRecord != null) { playerRecord.SessionsTogether++; } } } } lock (_dbLock) { _db.Sessions.Insert(0, _currentSession); SaveDatabase(); } } private Texture2D MakeTex(int width, int height, Color col) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown Color[] array = (Color[])(object)new Color[width * height]; for (int i = 0; i < array.Length; i++) { array[i] = col; } Texture2D val = new Texture2D(width, height); val.SetPixels(array); val.Apply(); return val; } private void OnGUI() { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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) if (_notificationTimer > 0f) { DrawNotification(); } if (_uiVisible) { if ((Object)(object)_modernBg == (Object)null) { _modernBg = MakeTex(1, 1, new Color(0.1f, 0.1f, 0.15f, 0.98f)); _modernHeader = MakeTex(1, 1, new Color(0.18f, 0.08f, 0.12f, 1f)); _modernBtn = MakeTex(1, 1, new Color(0.2f, 0.2f, 0.28f, 1f)); _modernBtnHover = MakeTex(1, 1, new Color(0.3f, 0.3f, 0.4f, 1f)); } _windowRect = GUI.Window(987654, _windowRect, new WindowFunction(DrawWindow), ""); } } private void DrawWindow(int id) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) GUI.DrawTexture(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width, ((Rect)(ref _windowRect)).height), (Texture)(object)_modernBg); float width = ((Rect)(ref _windowRect)).width; float height = ((Rect)(ref _windowRect)).height; if (_selectedSession != null) { DrawSessionDetail(0f, 0f, width, height); } else if (_selectedPlayer != null) { DrawPlayerDetail(0f, 0f, width, height); } else { DrawMainList(0f, 0f, width, height); } GUI.DragWindow(new Rect(0f, 0f, width, 30f)); } private void DrawMainList(float x, float y, float w, float h) { //IL_0009: 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_0028: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00be: 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_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: 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_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Expected O, but got Unknown //IL_0260: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0459: Unknown result type (might be due to invalid IL or missing references) //IL_046e: Unknown result type (might be due to invalid IL or missing references) //IL_0473: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Expected O, but got Unknown //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_04ce: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) GUI.DrawTexture(new Rect(x, y, w, 35f), (Texture)(object)_modernHeader); GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 18, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; GUI.color = new Color(1f, 0.4f, 0.4f, 1f); GUI.Label(new Rect(x, y + 5f, w, 30f), "R.E.P.O. CONTACTS", val); GUI.color = Color.white; GUIStyle val2 = new GUIStyle(GUI.skin.textField) { fontSize = 14 }; _searchQuery = GUI.TextField(new Rect(x + 15f, y + 45f, w - 30f, 25f), _searchQuery, val2); string[] array = new string[6] { "Recent", "Most Played", "Online", "Favorites", "Good Mates", "Once" }; float num = y + 77f; float num2 = (w - 30f) / (float)array.Length; for (int i = 0; i < array.Length; i++) { GUI.color = ((_currentFilter == i) ? new Color(0.4f, 0.2f, 0.2f, 1f) : new Color(0.15f, 0.15f, 0.2f, 1f)); if (GUI.Button(new Rect(x + 15f + (float)i * num2, num, num2 - 2f, 22f), array[i])) { _currentFilter = i; } } GUI.color = Color.white; List<PlayerRecord> filteredPlayers = GetFilteredPlayers(); _mainScroll = GUI.BeginScrollView(new Rect(x + 10f, y + 110f, w - 20f, h - 120f), _mainScroll, new Rect(0f, 0f, w - 40f, (float)(filteredPlayers.Count * 65 + 10))); GUIStyle val3 = new GUIStyle(GUI.skin.button) { alignment = (TextAnchor)3, fontSize = 14, richText = true, padding = new RectOffset(10, 10, 5, 5) }; float num3 = 5f; foreach (PlayerRecord item in filteredPlayers) { bool flag = _currentlyOnline.Contains(item.SteamId); bool flag2 = false; if (PhotonNetwork.IsConnected && PhotonNetwork.InRoom) { Player masterClient = PhotonNetwork.MasterClient; if (masterClient != null && masterClient.UserId == item.SteamId) { flag2 = true; } } Texture2D val4 = (item.IsFavorite ? _modernBtnHover : (flag ? _modernBtn : _modernBg)); GUI.DrawTexture(new Rect(5f, num3, w - 50f, 55f), (Texture)(object)val4); string text = (flag ? "\ud83d\udfe2" : "⚪"); string text2 = (item.IsFavorite ? "⭐ " : ""); string text3 = (flag2 ? " \ud83d\udc51" : ""); string text4 = text + " " + text2 + "<b>" + item.NickName + "</b>" + text3 + "\n" + $"<size=10>{item.SessionsTogether} sessions · {FormatTime(item.TotalSecondsPlayed)} · Last: {FormatRelativeTime(item.LastSeen)}</size>"; if (GUI.Button(new Rect(5f, num3, w - 50f, 55f), text4, val3)) { _selectedPlayer = item; _notesEditText = item.Notes ?? ""; _playerDetailTab = 0; } num3 += 60f; } GUI.EndScrollView(); GUI.color = new Color(0.5f, 0.5f, 0.5f, 1f); GUIStyle val5 = new GUIStyle(GUI.skin.label) { fontSize = 10, alignment = (TextAnchor)4 }; GUI.Label(new Rect(x, y + h - 20f, w, 20f), string.Format("[{0}] Close · {1} players · Author: {2}", ToggleKey.Value, filteredPlayers.Count, "3udah"), val5); GUI.color = Color.white; } private void DrawPlayerDetail(float x, float y, float w, float h) { //IL_001c: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0065: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) if (_selectedPlayer == null) { return; } GUI.DrawTexture(new Rect(x, y, w, 35f), (Texture)(object)_modernHeader); GUIStyle val = new GUIStyle(GUI.skin.button) { fontSize = 14, alignment = (TextAnchor)3 }; if (GUI.Button(new Rect(x + 10f, y + 5f, 80f, 25f), "← Back", val)) { _selectedPlayer = null; _editingNotes = false; return; } GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 16, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; GUI.color = new Color(1f, 0.4f, 0.4f, 1f); GUI.Label(new Rect(x + 90f, y + 5f, w - 100f, 25f), _selectedPlayer.NickName.ToUpper(), val2); GUI.color = Color.white; string[] array = new string[3] { "Overview", "Sessions", "Notes" }; float num = y + 40f; float num2 = (w - 20f) / (float)array.Length; for (int i = 0; i < array.Length; i++) { GUI.color = ((_playerDetailTab == i) ? new Color(0.4f, 0.2f, 0.2f, 1f) : new Color(0.15f, 0.15f, 0.2f, 1f)); if (GUI.Button(new Rect(x + 10f + (float)i * num2, num, num2 - 2f, 25f), array[i])) { _playerDetailTab = i; if (i == 2) { _notesEditText = _selectedPlayer.Notes ?? ""; } } } GUI.color = Color.white; _detailScroll = GUI.BeginScrollView(new Rect(x + 10f, y + 75f, w - 20f, h - 85f), _detailScroll, new Rect(0f, 0f, w - 40f, h)); float startY = 10f; switch (_playerDetailTab) { case 0: startY = DrawPlayerOverview(startY, w); break; case 1: startY = DrawPlayerSessions(startY, w); break; case 2: startY = DrawPlayerNotes(startY, w); break; } GUI.EndScrollView(); } private float DrawPlayerOverview(float startY, float w) { //IL_0058: 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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_01a3: 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) bool flag = _currentlyOnline.Contains(_selectedPlayer.SteamId); string text = (flag ? "\ud83d\udfe2 ONLINE" : "\ud83d\udd34 OFFLINE"); GUI.color = (flag ? new Color(0.3f, 0.8f, 0.3f, 1f) : new Color(0.8f, 0.3f, 0.3f, 1f)); GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 14, fontStyle = (FontStyle)1 }; GUI.Label(new Rect(10f, startY, w - 20f, 25f), text, val); GUI.color = Color.white; startY += 35f; if (GUI.Button(new Rect(10f, startY, w - 20f, 30f), "\ud83c\udf10 Open Steam Profile")) { Application.OpenURL("https://steamcommunity.com/profiles/" + _selectedPlayer.SteamId); } startY += 40f; GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 13, richText = true }; string text2 = $"<b>Sessions:</b> {_selectedPlayer.SessionsTogether}\n" + "<b>Time Together:</b> " + FormatTime(_selectedPlayer.TotalSecondsPlayed) + "\n<b>First Seen:</b> " + _selectedPlayer.FirstSeen + "\n<b>Last Seen:</b> " + _selectedPlayer.LastSeen; GUI.Label(new Rect(10f, startY, w - 20f, 100f), text2, val2); startY += 110f; if (GUI.Button(new Rect(10f, startY, w - 20f, 30f), _selectedPlayer.IsFavorite ? "⭐ Remove Favorite" : "☆ Add Favorite")) { _selectedPlayer.IsFavorite = !_selectedPlayer.IsFavorite; lock (_dbLock) { SaveDatabase(); } } return startY + 40f; } private float DrawPlayerSessions(float startY, float w) { //IL_000b: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_007e: 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) GUIStyle val = new GUIStyle(GUI.skin.button) { alignment = (TextAnchor)3, fontSize = 12, richText = true }; List<SessionRecord> list = _db.Sessions.Where((SessionRecord s) => s.PlayerSteamIdsCombined.Contains(_selectedPlayer.SteamId)).ToList(); if (list.Count == 0) { GUI.Label(new Rect(10f, startY, w - 20f, 30f), "No sessions recorded yet.", val); return startY + 35f; } foreach (SessionRecord item in list) { string text = (item.RunSucceeded ? "✅" : "❌"); string text2 = text + " <b>" + item.Date + "</b>\n" + $"<size=10>Level {item.LevelReached} · {FormatTime(item.DurationSeconds)}</size>"; if (GUI.Button(new Rect(10f, startY, w - 20f, 45f), text2, val)) { _selectedSession = item; } startY += 50f; } return startY; } private float DrawPlayerNotes(float startY, float w) { //IL_000b: 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_001a: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Expected O, but got Unknown //IL_0065: 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_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_018d: 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) GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 13 }; GUI.Label(new Rect(10f, startY, w - 20f, 20f), "Personal Notes:", val); startY += 25f; if (_editingNotes) { _notesEditText = GUI.TextArea(new Rect(10f, startY, w - 20f, 150f), _notesEditText, 1000); startY += 155f; if (GUI.Button(new Rect(10f, startY, 80f, 25f), "Save")) { _selectedPlayer.Notes = _notesEditText; _editingNotes = false; lock (_dbLock) { SaveDatabase(); } } if (GUI.Button(new Rect(100f, startY, 80f, 25f), "Cancel")) { _editingNotes = false; _notesEditText = _selectedPlayer.Notes ?? ""; } } else { GUIStyle val2 = new GUIStyle(GUI.skin.box) { fontSize = 12, wordWrap = true }; string text = (string.IsNullOrEmpty(_selectedPlayer.Notes) ? "No notes yet." : _selectedPlayer.Notes); GUI.Box(new Rect(10f, startY, w - 20f, 150f), text, val2); startY += 155f; if (GUI.Button(new Rect(10f, startY, 100f, 25f), "✏\ufe0f Edit Notes")) { _editingNotes = true; _notesEditText = _selectedPlayer.Notes ?? ""; } } return startY + 35f; } private void DrawSessionDetail(float x, float y, float w, float h) { //IL_001c: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00c4: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Expected O, but got Unknown //IL_021a: 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_030f: Unknown result type (might be due to invalid IL or missing references) if (_selectedSession == null) { return; } GUI.DrawTexture(new Rect(x, y, w, 35f), (Texture)(object)_modernHeader); GUIStyle val = new GUIStyle(GUI.skin.button) { fontSize = 14, alignment = (TextAnchor)3 }; if (GUI.Button(new Rect(x + 10f, y + 5f, 80f, 25f), "← Back", val)) { _selectedSession = null; return; } GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 16, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; GUI.color = new Color(1f, 0.4f, 0.4f, 1f); GUI.Label(new Rect(x + 90f, y + 5f, w - 100f, 25f), "SESSION DETAILS", val2); GUI.color = Color.white; _sessionScroll = GUI.BeginScrollView(new Rect(x + 10f, y + 45f, w - 20f, h - 55f), _sessionScroll, new Rect(0f, 0f, w - 40f, h + 200f)); float num = 10f; GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = 13, richText = true }; string text = "<b>Date:</b> " + _selectedSession.Date + "\n" + $"<b>Level:</b> {_selectedSession.LevelName} (Reached {_selectedSession.LevelReached})\n" + "<b>Duration:</b> " + FormatTime(_selectedSession.DurationSeconds) + "\n<b>Result:</b> " + (_selectedSession.RunSucceeded ? "✅ Success" : "❌ Failed"); GUI.Label(new Rect(10f, num, w - 20f, 100f), text, val3); num += 110f; GUI.Label(new Rect(10f, num, w - 20f, 20f), "<b>\ud83d\udc65 Squad:</b>", val3); num += 25f; if (!string.IsNullOrEmpty(_selectedSession.PlayerSteamIdsCombined)) { string[] array = _selectedSession.PlayerSteamIdsCombined.Split(new char[1] { ',' }); string[] array2 = array; foreach (string id in array2) { if (!string.IsNullOrEmpty(id)) { PlayerRecord playerRecord = _db.Players.Find((PlayerRecord p) => p.SteamId == id); string text2 = ((playerRecord != null) ? playerRecord.NickName : "Unknown Player"); if (GUI.Button(new Rect(10f, num, w - 20f, 25f), text2) && playerRecord != null) { _selectedPlayer = playerRecord; _selectedSession = null; _playerDetailTab = 0; } num += 30f; } } } GUI.EndScrollView(); } private void DrawNotification() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: 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) float num = 300f; float num2 = 80f; float num3 = (float)Screen.width - num - 20f; float num4 = 20f; float num5 = Mathf.Clamp(_notificationTimer / _notificationDuration, 0f, 1f); Color col = default(Color); ((Color)(ref col))..ctor(0.1f, 0.1f, 0.15f, num5 * 0.95f); Texture2D val = MakeTex(1, 1, col); GUI.DrawTexture(new Rect(num3, num4, num, num2), (Texture)(object)val); GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 12, richText = true, wordWrap = true, alignment = (TextAnchor)3 }; GUI.color = new Color(1f, 1f, 1f, num5); GUI.Label(new Rect(num3 + 10f, num4 + 10f, num - 20f, num2 - 20f), _notificationText, val2); GUI.color = Color.white; } private List<PlayerRecord> GetFilteredPlayers() { lock (_dbLock) { IEnumerable<PlayerRecord> source = _db.Players.AsEnumerable(); if (!string.IsNullOrEmpty(_searchQuery)) { string q = _searchQuery.ToLower(); source = source.Where((PlayerRecord p) => p.NickName.ToLower().Contains(q)); } switch (_currentFilter) { case 0: source = source.OrderByDescending((PlayerRecord p) => p.LastSeen); break; case 1: source = source.OrderByDescending((PlayerRecord p) => p.SessionsTogether); break; case 2: source = source.Where((PlayerRecord p) => _currentlyOnline.Contains(p.SteamId)); break; case 3: source = source.Where((PlayerRecord p) => p.IsFavorite); break; case 4: source = source.OrderByDescending((PlayerRecord p) => p.SessionsTogether); break; case 5: source = source.Where((PlayerRecord p) => p.SessionsTogether <= 1); break; } return source.ToList(); } } private void LoadDatabase() { try { if (!File.Exists(SaveFile)) { Logger.LogWarning((object)"contacts.json not found. Creating new database."); _db = new ContactsDatabase(); return; } string text = File.ReadAllText(SaveFile); Logger.LogInfo((object)$"Read {text.Length} bytes from contacts.json."); _db = new ContactsDatabase(); if (text.Contains("\"Players\":[")) { int num = text.IndexOf("\"Players\":[") + 11; int num2 = text.IndexOf("],\"Sessions\""); if (num2 == -1) { num2 = text.LastIndexOf("]"); } if (num2 > num) { string text2 = text.Substring(num, num2 - num); string[] array = text2.Split(new string[1] { "},{" }, StringSplitOptions.None); string[] array2 = array; foreach (string text3 in array2) { string json = text3.Trim().TrimStart(new char[1] { '{' }).TrimEnd(new char[1] { '}' }); PlayerRecord playerRecord = new PlayerRecord { SteamId = ExtractJsonField(json, "SteamId"), NickName = ExtractJsonField(json, "NickName"), FirstSeen = ExtractJsonField(json, "FirstSeen"), LastSeen = ExtractJsonField(json, "LastSeen"), Notes = ExtractJsonField(json, "Notes") }; int.TryParse(ExtractJsonRaw(json, "SessionsTogether"), out playerRecord.SessionsTogether); int.TryParse(ExtractJsonRaw(json, "TotalSecondsPlayed"), out playerRecord.TotalSecondsPlayed); bool.TryParse(ExtractJsonRaw(json, "IsFavorite"), out playerRecord.IsFavorite); _db.Players.Add(playerRecord); } } } Logger.LogInfo((object)$"Loaded {_db.Players.Count} players."); } catch (Exception arg) { Logger.LogError((object)$"Failed to load database: {arg}"); _db = new ContactsDatabase(); } } private string ExtractJsonField(string json, string fieldName) { string text = "\"" + fieldName + "\":\""; int num = json.IndexOf(text); if (num == -1) { return ""; } num += text.Length; int num2 = json.IndexOf("\",", num); if (num2 == -1) { num2 = json.IndexOf("\"", num); } return json.Substring(num, num2 - num); } private string ExtractJsonRaw(string json, string fieldName) { string text = "\"" + fieldName + "\":"; int num = json.IndexOf(text); if (num == -1) { return ""; } num += text.Length; int num2 = json.IndexOf(",", num); if (num2 == -1) { num2 = json.IndexOf("}", num); } return json.Substring(num, num2 - num).Trim(); } private static void SaveDatabase() { try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{"); stringBuilder.Append("\"Players\":["); for (int i = 0; i < _db.Players.Count; i++) { PlayerRecord playerRecord = _db.Players[i]; if (i > 0) { stringBuilder.Append(","); } stringBuilder.Append("{"); stringBuilder.Append("\"SteamId\":\"" + EscapeJson(playerRecord.SteamId) + "\","); stringBuilder.Append("\"NickName\":\"" + EscapeJson(playerRecord.NickName) + "\","); stringBuilder.Append("\"FirstSeen\":\"" + EscapeJson(playerRecord.FirstSeen) + "\","); stringBuilder.Append("\"LastSeen\":\"" + EscapeJson(playerRecord.LastSeen) + "\","); stringBuilder.Append($"\"SessionsTogether\":{playerRecord.SessionsTogether},"); stringBuilder.Append($"\"TotalSecondsPlayed\":{playerRecord.TotalSecondsPlayed},"); stringBuilder.Append("\"IsFavorite\":" + (playerRecord.IsFavorite ? "true" : "false") + ","); stringBuilder.Append("\"Notes\":\"" + EscapeJson(playerRecord.Notes ?? "") + "\""); stringBuilder.Append("}"); } stringBuilder.Append("],"); stringBuilder.Append("\"Sessions\":["); for (int j = 0; j < _db.Sessions.Count; j++) { SessionRecord sessionRecord = _db.Sessions[j]; if (j > 0) { stringBuilder.Append(","); } stringBuilder.Append("{"); stringBuilder.Append("\"SessionId\":\"" + EscapeJson(sessionRecord.SessionId) + "\","); stringBuilder.Append("\"Date\":\"" + EscapeJson(sessionRecord.Date) + "\","); stringBuilder.Append("\"LevelName\":\"" + EscapeJson(sessionRecord.LevelName) + "\","); stringBuilder.Append($"\"LevelReached\":{sessionRecord.LevelReached},"); stringBuilder.Append($"\"TotalValue\":{sessionRecord.TotalValue},"); stringBuilder.Append("\"RunSucceeded\":" + (sessionRecord.RunSucceeded ? "true" : "false") + ","); stringBuilder.Append($"\"DurationSeconds\":{sessionRecord.DurationSeconds},"); stringBuilder.Append("\"PlayerSteamIdsCombined\":\"" + EscapeJson(sessionRecord.PlayerSteamIdsCombined ?? "") + "\""); stringBuilder.Append("}"); } stringBuilder.Append("]"); stringBuilder.Append("}"); string text = stringBuilder.ToString(); File.WriteAllText(SaveFile, text); Logger.LogInfo((object)$"[SAVE] Wrote {text.Length} bytes to contacts.json"); } catch (Exception ex) { Logger.LogError((object)("Failed to save database: " + ex.Message)); } } private static string EscapeJson(string str) { if (string.IsNullOrEmpty(str)) { return ""; } return str.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n") .Replace("\r", "\\r"); } private static string FormatTime(int seconds) { if (seconds < 60) { return $"{seconds}s"; } if (seconds < 3600) { return $"{seconds / 60}m"; } return $"{seconds / 3600}h {seconds % 3600 / 60}m"; } private static string FormatRelativeTime(string lastSeen) { try { DateTime dateTime = DateTime.Parse(lastSeen); TimeSpan timeSpan = DateTime.Now - dateTime; if (timeSpan.TotalMinutes < 1.0) { return "just now"; } if (timeSpan.TotalMinutes < 60.0) { return $"{(int)timeSpan.TotalMinutes}m ago"; } if (timeSpan.TotalHours < 24.0) { return $"{(int)timeSpan.TotalHours}h ago"; } if (timeSpan.TotalDays < 7.0) { return $"{(int)timeSpan.TotalDays}d ago"; } return dateTime.ToString("MMM dd"); } catch { return lastSeen; } } }