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 PlayerReportCard v1.0.2
EmpressPerformanceReport.dll
Decompiled 4 months 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.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Omniscye")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EmpressPerformanceReport")] [assembly: AssemblyTitle("EmpressPerformanceReport")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace PerformanceReport { [BepInPlugin("com.EMpress.performancereport", "Performance Report", "1.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class PerformanceReportPlugin : BaseUnityPlugin { public static PerformanceReportPlugin Instance; public static ReportManager Manager; private Harmony _harmony; private void Awake() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); Instance = this; Manager = new ReportManager(); _harmony = new Harmony("com.EMpress.performancereport"); _harmony.PatchAll(); MenuAPI.AddElementToEscapeMenu(new BuilderDelegate(CreateMenuButton)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Performance Report (Host Only) loaded!"); } private void CreateMenuButton(Transform parent) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) MenuAPI.CreateREPOButton("PLAYER RATINGS", (Action)delegate { PerformanceUI.OpenRatingsMenu(); }, parent, Vector2.zero); } } [Serializable] public class PlayerSessionStats { public string SteamID; public string LastKnownName; public int TotalGames; public int TotalDeaths; public int TotalDamageTaken; public int TotalExtracts; public float AverageGradePoint; public long LastSeen; public string GetGrade() { if (AverageGradePoint >= 4.5f) { return "<color=#FFD700>S+</color>"; } if (AverageGradePoint >= 4f) { return "<color=#00FF00>A</color>"; } if (AverageGradePoint >= 3f) { return "<color=#ADFF2F>B</color>"; } if (AverageGradePoint >= 2f) { return "<color=#FFA500>C</color>"; } if (AverageGradePoint >= 1f) { return "<color=#FF4500>D</color>"; } return "<color=#FF0000>F</color>"; } } [Serializable] public class SavedData { public List<PlayerSessionStats> Players = new List<PlayerSessionStats>(); } public class SessionTracker { public string SteamID; public string Name; public int DamageTaken; public bool Died; public bool Extracted; } public class ReportManager { public Dictionary<string, SessionTracker> CurrentSession = new Dictionary<string, SessionTracker>(); public SavedData PersistentData = new SavedData(); private string _savePath; private bool _roundCommitted = false; public ReportManager() { _savePath = Path.Combine(Paths.ConfigPath, "PerformanceReport_Data.json"); Load(); } public void ResetRound() { CurrentSession.Clear(); _roundCommitted = false; if (!((Object)(object)GameDirector.instance != (Object)null) || GameDirector.instance.PlayerList == null) { return; } foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if ((Object)(object)player != (Object)null) { string realSteamID = GetRealSteamID(player); RegisterPlayer(realSteamID, player.playerName); } } } public void RegisterPlayer(string steamID, string name) { if (!string.IsNullOrEmpty(steamID)) { if (!CurrentSession.ContainsKey(steamID)) { CurrentSession.Add(steamID, new SessionTracker { SteamID = steamID, Name = name, DamageTaken = 0, Died = false, Extracted = false }); } else if (!string.IsNullOrEmpty(name) && name != "Unknown") { CurrentSession[steamID].Name = name; } } } public void EndRound() { if (_roundCommitted) { return; } if ((Object)(object)GameDirector.instance != (Object)null && GameDirector.instance.PlayerList != null) { foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if ((Object)(object)player != (Object)null) { string realSteamID = GetRealSteamID(player); bool deadSet = player.deadSet; bool flag = (Object)(object)player.RoomVolumeCheck != (Object)null && player.RoomVolumeCheck.inTruck; if (!deadSet && flag) { TrackExtract(realSteamID, player.playerName); } } } } if (CurrentSession.Count == 0) { return; } foreach (SessionTracker value in CurrentSession.Values) { float num = 5f; if (value.Died) { num -= 3f; } else if (value.DamageTaken > 50) { num -= 1f; } else if (value.DamageTaken > 20) { num -= 0.5f; } if (!value.Extracted && !value.Died) { num -= 1f; } if (value.Extracted) { num += 0.5f; } num = Mathf.Clamp(num, 0f, 5.5f); UpdatePersistentStats(value, num); } Save(); _roundCommitted = true; } public void TrackDamage(string steamID, int amount) { if (!string.IsNullOrEmpty(steamID) && !_roundCommitted) { if (!CurrentSession.ContainsKey(steamID)) { RegisterPlayer(steamID, "Unknown"); } if (CurrentSession.TryGetValue(steamID, out SessionTracker value)) { value.DamageTaken += amount; } } } public void TrackDeath(string steamID) { if (!string.IsNullOrEmpty(steamID) && !_roundCommitted) { if (!CurrentSession.ContainsKey(steamID)) { RegisterPlayer(steamID, "Unknown"); } if (CurrentSession.TryGetValue(steamID, out SessionTracker value)) { value.Died = true; } } } public void TrackExtract(string steamID, string name) { if (!string.IsNullOrEmpty(steamID)) { if (!CurrentSession.ContainsKey(steamID)) { RegisterPlayer(steamID, name); } if (CurrentSession.TryGetValue(steamID, out SessionTracker value)) { value.Extracted = true; } } } public string GetRealSteamID(PlayerAvatar player) { if ((Object)(object)player == (Object)null) { return null; } try { FieldInfo field = typeof(PlayerAvatar).GetField("steamID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { string text = (string)field.GetValue(player); if (!string.IsNullOrEmpty(text)) { return text; } } } catch { } if ((Object)(object)player.photonView != (Object)null && player.photonView.Owner != null) { return player.photonView.Owner.UserId; } return null; } private void UpdatePersistentStats(SessionTracker current, float roundGrade) { SessionTracker current2 = current; PlayerSessionStats playerSessionStats = PersistentData.Players.FirstOrDefault((PlayerSessionStats p) => p.SteamID == current2.SteamID); if (playerSessionStats == null) { playerSessionStats = new PlayerSessionStats { SteamID = current2.SteamID, AverageGradePoint = roundGrade, TotalGames = 0 }; PersistentData.Players.Add(playerSessionStats); } playerSessionStats.LastKnownName = current2.Name; playerSessionStats.TotalGames++; playerSessionStats.TotalDamageTaken += current2.DamageTaken; playerSessionStats.LastSeen = DateTime.UtcNow.Ticks; if (current2.Died) { playerSessionStats.TotalDeaths++; } if (current2.Extracted) { playerSessionStats.TotalExtracts++; } playerSessionStats.AverageGradePoint = (playerSessionStats.AverageGradePoint * (float)(playerSessionStats.TotalGames - 1) + roundGrade) / (float)playerSessionStats.TotalGames; } public void Save() { try { string contents = JsonUtility.ToJson((object)PersistentData, true); File.WriteAllText(_savePath, contents); } catch (Exception arg) { Debug.LogError((object)$"Failed to save stats: {arg}"); } } public void Load() { if (!File.Exists(_savePath)) { return; } try { string text = File.ReadAllText(_savePath); PersistentData = JsonUtility.FromJson<SavedData>(text); } catch (Exception arg) { Debug.LogError((object)$"Failed to load stats: {arg}"); } } } [HarmonyPatch] public static class Patches { [HarmonyPatch(typeof(LevelGenerator), "Start")] [HarmonyPostfix] public static void OnLevelStart() { if (PhotonNetwork.IsMasterClient) { PerformanceReportPlugin.Manager.ResetRound(); } } [HarmonyPatch(typeof(GameDirector), "OutroStart")] [HarmonyPostfix] public static void OnOutroStart() { if (PhotonNetwork.IsMasterClient) { PerformanceReportPlugin.Manager.EndRound(); } } [HarmonyPatch(typeof(PlayerHealth), "Hurt")] [HarmonyPrefix] public static void OnHurtPrefix(PlayerHealth __instance, out int __state) { __state = __instance.health; } [HarmonyPatch(typeof(PlayerHealth), "Hurt")] [HarmonyPostfix] public static void OnHurtPostfix(PlayerHealth __instance, int __state) { if (!PhotonNetwork.IsMasterClient || (Object)(object)__instance == (Object)null || SemiFunc.RunIsShop() || SemiFunc.RunIsLobbyMenu()) { return; } int num = __state - __instance.health; if (num <= 0) { return; } PlayerAvatar component = ((Component)__instance).GetComponent<PlayerAvatar>(); if ((Object)(object)component != (Object)null) { string realSteamID = PerformanceReportPlugin.Manager.GetRealSteamID(component); if (!string.IsNullOrEmpty(realSteamID)) { PerformanceReportPlugin.Manager.TrackDamage(realSteamID, num); PerformanceReportPlugin.Manager.RegisterPlayer(realSteamID, component.playerName); } } } [HarmonyPatch(typeof(PlayerHealth), "UpdateHealthRPC")] [HarmonyPrefix] public static void OnUpdateHealthRPC(PlayerHealth __instance, int healthNew, int healthMax, bool effect) { if (!PhotonNetwork.IsMasterClient || (Object)(object)__instance == (Object)null || SemiFunc.RunIsShop() || SemiFunc.RunIsLobbyMenu()) { return; } int health = __instance.health; bool flag = false; try { flag = (bool)AccessTools.Field(typeof(PlayerHealth), "healthSet").GetValue(__instance); } catch { } if (!(flag && effect) || healthNew >= health) { return; } int amount = health - healthNew; PlayerAvatar component = ((Component)__instance).GetComponent<PlayerAvatar>(); if ((Object)(object)component != (Object)null) { string realSteamID = PerformanceReportPlugin.Manager.GetRealSteamID(component); if (!string.IsNullOrEmpty(realSteamID)) { PerformanceReportPlugin.Manager.TrackDamage(realSteamID, amount); PerformanceReportPlugin.Manager.RegisterPlayer(realSteamID, component.playerName); } } } [HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathRPC")] [HarmonyPostfix] public static void OnPlayerDeathRPC(PlayerAvatar __instance) { if (PhotonNetwork.IsMasterClient && !((Object)(object)__instance == (Object)null)) { string realSteamID = PerformanceReportPlugin.Manager.GetRealSteamID(__instance); if (!string.IsNullOrEmpty(realSteamID)) { PerformanceReportPlugin.Manager.TrackDeath(realSteamID); } } } [HarmonyPatch(typeof(PlayerAvatar), "AddToStatsManagerRPC")] [HarmonyPostfix] public static void OnStatsSynced(PlayerAvatar __instance, string _playerName, string _steamID) { if (PhotonNetwork.IsMasterClient && !string.IsNullOrEmpty(_steamID)) { PerformanceReportPlugin.Manager.RegisterPlayer(_steamID, _playerName); } } } public static class PerformanceUI { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ScrollViewBuilderDelegate <>9__2_0; public static Func<PlayerSessionStats, long> <>9__2_1; public static ScrollViewBuilderDelegate <>9__2_2; internal RectTransform <OpenRatingsMenu>b__2_0(Transform scrollRect) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) REPOLabel val = MenuAPI.CreateREPOLabel("<color=#FFFF00>NAME / GRADE</color>", scrollRect, default(Vector2)); return ((REPOElement)val).rectTransform; } internal long <OpenRatingsMenu>b__2_1(PlayerSessionStats x) { return x.LastSeen; } internal RectTransform <OpenRatingsMenu>b__2_2(Transform scrollRect) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) return ((REPOElement)MenuAPI.CreateREPOLabel("No data recorded yet...", scrollRect, default(Vector2))).rectTransform; } } private static REPOPopupPage _ratingPage; private static REPOPopupPage _detailPage; public static void OpenRatingsMenu() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown if ((Object)(object)_ratingPage != (Object)null) { _ratingPage.ClosePage(false); Object.Destroy((Object)(object)((Component)_ratingPage).gameObject); } _ratingPage = MenuAPI.CreateREPOPopupPage("PLAYER REPORT CARD", (PresetSide)1, false, true, 5f); REPOPopupPage ratingPage = _ratingPage; object obj = <>c.<>9__2_0; if (obj == null) { ScrollViewBuilderDelegate val = delegate(Transform scrollRect) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) REPOLabel val4 = MenuAPI.CreateREPOLabel("<color=#FFFF00>NAME / GRADE</color>", scrollRect, default(Vector2)); return ((REPOElement)val4).rectTransform; }; <>c.<>9__2_0 = val; obj = (object)val; } ratingPage.AddElementToScrollView((ScrollViewBuilderDelegate)obj, 0f, 15f); List<PlayerSessionStats> list = PerformanceReportPlugin.Manager.PersistentData.Players.OrderByDescending((PlayerSessionStats x) => x.LastSeen).ToList(); if (list.Count == 0) { REPOPopupPage ratingPage2 = _ratingPage; object obj2 = <>c.<>9__2_2; if (obj2 == null) { ScrollViewBuilderDelegate val2 = (Transform scrollRect) => ((REPOElement)MenuAPI.CreateREPOLabel("No data recorded yet...", scrollRect, default(Vector2))).rectTransform; <>c.<>9__2_2 = val2; obj2 = (object)val2; } ratingPage2.AddElementToScrollView((ScrollViewBuilderDelegate)obj2, 0f, 0f); } else { foreach (PlayerSessionStats player in list) { _ratingPage.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollRect) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) string text = player.LastKnownName + " - [" + player.GetGrade() + "]"; REPOButton val3 = MenuAPI.CreateREPOButton(text, (Action)delegate { OpenDetailMenu(player); }, scrollRect, Vector2.zero); return ((REPOElement)val3).rectTransform; }, 0f, 5f); } } _ratingPage.OpenPage(false); } public static void OpenDetailMenu(PlayerSessionStats player) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected O, but got Unknown PlayerSessionStats player2 = player; if ((Object)(object)_detailPage != (Object)null) { _detailPage.ClosePage(false); Object.Destroy((Object)(object)((Component)_detailPage).gameObject); } _detailPage = MenuAPI.CreateREPOPopupPage("DETAILS: " + player2.LastKnownName, true, true, 2f, (Vector2?)null); _detailPage.AddElementToScrollView((ScrollViewBuilderDelegate)((Transform scrollRect) => ((REPOElement)MenuAPI.CreateREPOLabel("<color=#888888>Grade:</color> " + player2.GetGrade(), scrollRect, default(Vector2))).rectTransform), 0f, 5f); _detailPage.AddElementToScrollView((ScrollViewBuilderDelegate)((Transform scrollRect) => ((REPOElement)MenuAPI.CreateREPOLabel($"<color=#888888>Games Tracked:</color> {player2.TotalGames}", scrollRect, default(Vector2))).rectTransform), 0f, 5f); string survival = ((player2.TotalGames > 0) ? (100f * (float)player2.TotalExtracts / (float)player2.TotalGames).ToString("0") : "0") + "%"; _detailPage.AddElementToScrollView((ScrollViewBuilderDelegate)((Transform scrollRect) => ((REPOElement)MenuAPI.CreateREPOLabel("<color=#888888>Survival Rate:</color> " + survival, scrollRect, default(Vector2))).rectTransform), 0f, 5f); _detailPage.AddElementToScrollView((ScrollViewBuilderDelegate)((Transform scrollRect) => ((REPOElement)MenuAPI.CreateREPOLabel($"<color=#888888>Total Deaths:</color> <color=red>{player2.TotalDeaths}</color>", scrollRect, default(Vector2))).rectTransform), 0f, 5f); _detailPage.AddElementToScrollView((ScrollViewBuilderDelegate)((Transform scrollRect) => ((REPOElement)MenuAPI.CreateREPOLabel($"<color=#888888>Total Dmg Taken:</color> {player2.TotalDamageTaken}", scrollRect, default(Vector2))).rectTransform), 0f, 20f); _detailPage.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollRect) { //IL_0028: 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) REPOButton val = MenuAPI.CreateREPOButton("FORGET PLAYER", (Action)delegate { PerformanceReportPlugin.Manager.PersistentData.Players.Remove(player2); PerformanceReportPlugin.Manager.Save(); _detailPage.ClosePage(false); OpenRatingsMenu(); }, scrollRect, default(Vector2)); return ((REPOElement)val).rectTransform; }, 0f, 0f); _detailPage.OpenPage(true); } } }