Decompiled source of PlayerReportCard v1.0.0

EmpressPerformanceReport.dll

Decompiled 2 days ago
using 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);
		}
	}
}