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);
}
}
}