using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using HighQuotaHelper; using HighQuotaStatTracking; using HighQuotaStatTracking.Patches; using Microsoft.CodeAnalysis; using StaticNetcodeLib; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("HighQuotaStatTracking")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+6f28c97710ae725214e9362713f8aa84c1019302")] [assembly: AssemblyProduct("My first plugin")] [assembly: AssemblyTitle("HighQuotaStatTracking")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace HighQuotaHelper { [StaticNetcode] public class NetworkRPC { public delegate void ReceivedStats(ClientPlayer player); public delegate void ReceivedPickupItem(ulong networkID, ulong steamID); public delegate void ReceivedLog(string displayName, ulong steamID, LogLevel logLevel, string message, bool logOnServer); public static event ReceivedStats OnReceivedStats; public static event ReceivedPickupItem OnReceivedPickupItem; public static event ReceivedLog OnReceivedLog; [ServerRpc(RequireOwnership = false)] public static void ReportStatsServerRpc(ClientPlayer playerStats) { if (NetworkRPC.OnReceivedStats != null) { NetworkRPC.OnReceivedStats(playerStats); } } [ServerRpc(RequireOwnership = false)] public static void ReportPickedUpObjectServerRpc(ulong networkID, ulong steamID) { if (NetworkRPC.OnReceivedPickupItem != null) { NetworkRPC.OnReceivedPickupItem(networkID, steamID); } } [ServerRpc(RequireOwnership = false)] public static void LogServerRpc(string displayName, ulong steamID, LogLevel logLevel, string message, bool logOnServer) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (NetworkRPC.OnReceivedLog != null) { NetworkRPC.OnReceivedLog(displayName, steamID, logLevel, message, logOnServer); } } } } namespace HighQuotaStatTracking { public class ClientPlayer { public ulong SteamID { get; set; } public DateTime? DiedTime { get; set; } public ushort Jumps { get; set; } public short DoorsOpened { get; set; } public float DistanceTraveled { get; set; } public float DistanceJetpacked { get; set; } public float DistanceCrouched { get; set; } public float DistanceSprinted { get; set; } public float DistanceWalked { get; set; } public float DistanceLaddered { get; set; } public float DistanceCruisered { get; set; } public TimeSpan TotalWalkieTime { get; set; } public float TotalFlashlightTime { get; set; } public ushort DamageTaken { get; set; } public float TotalStamina { get; set; } public int StaminaCounts { get; set; } public float TimeSpentAbove19PoundsInside { get; set; } public float TZPHighTime { get; set; } public Dictionary ObtainedItems { get; set; } = new Dictionary(); } [BepInPlugin("HighQuotaStatTracking", "High Quota Stat Tracking", "1.12.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "HighQuotaStatTracking"; public const string PluginName = "High Quota Stat Tracking"; public const string PluginVersion = "1.12.1"; internal static ManualLogSource LogSource; private readonly Harmony harmony = new Harmony("HighQuotaStatTracking"); private void Awake() { LogSource = ((BaseUnityPlugin)this).Logger; LogSource.LogInfo((object)"Plugin HighQuotaStatTracking is loaded!"); harmony.PatchAll(typeof(StartOfRoundPatch)); harmony.PatchAll(typeof(PlayerControllerBPatch)); harmony.PatchAll(typeof(WalkieTalkiePatch)); harmony.PatchAll(typeof(DoorLockPatch)); harmony.PatchAll(typeof(BeltBagItemPatch)); harmony.PatchAll(typeof(VehicleControllerPatch)); LogSource.LogInfo((object)"Patched"); } } public class StatManager { private static StatManager _instance; public static StatManager Instance { get { if (_instance == null) { _instance = new StatManager(); } return _instance; } } public bool IsOnMoon { get; private set; } public ClientPlayer LocalPlayer { get; private set; } public DateTime LandedTime { get; private set; } public void ResetLocalPlayer() { LocalPlayer = new ClientPlayer { SteamID = GameNetworkManager.Instance.localPlayerController.playerSteamId }; } public void StartRound() { ResetLocalPlayer(); IsOnMoon = true; LandedTime = DateTime.UtcNow; GrabbableObject[] itemSlots = GameNetworkManager.Instance.localPlayerController.ItemSlots; foreach (GrabbableObject val in itemSlots) { if ((Object)(object)val != (Object)null) { TrackObjectGrabbed(((NetworkBehaviour)val).NetworkObjectId); } } if ((Object)(object)GameNetworkManager.Instance.localPlayerController.ItemOnlySlot != (Object)null) { TrackObjectGrabbed(((NetworkBehaviour)GameNetworkManager.Instance.localPlayerController.ItemOnlySlot).NetworkObjectId); } } public void EndRound() { WalkieTalkiePatch.StartUseTime = null; IsOnMoon = false; NetworkRPC.ReportStatsServerRpc(LocalPlayer); } public void TrackObjectGrabbed(ulong networkID) { Utils.Log((LogLevel)32, $"Sending object grabbed {networkID} {GameNetworkManager.Instance.localPlayerController.playerSteamId}"); NetworkRPC.ReportPickedUpObjectServerRpc(networkID, GameNetworkManager.Instance.localPlayerController.playerSteamId); } } public static class Utils { public static void Log(LogLevel logLevel, string message, ManualLogSource logSource = null) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (logSource == null) { Plugin.LogSource.Log(logLevel, (object)message); } else { logSource.Log(logLevel, (object)message); } if ((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null) { NetworkRPC.LogServerRpc(GameNetworkManager.Instance.localPlayerController.playerUsername, GameNetworkManager.Instance.localPlayerController.playerSteamId, logLevel, message, logSource == null); } } } } namespace HighQuotaStatTracking.Patches { public static class BeltBagItemPatch { [HarmonyPrefix] [HarmonyPatch(typeof(BeltBagItem), "PutObjectInBagLocalClient")] private static void PutObjectInBagLocalClient(GrabbableObject gObject, BeltBagItem __instance) { if (!((Object)(object)((GrabbableObject)__instance).playerHeldBy == (Object)null) && StatManager.Instance.IsOnMoon && GameNetworkManager.Instance.localPlayerController.playerSteamId == ((GrabbableObject)__instance).playerHeldBy.playerSteamId) { StatManager.Instance.TrackObjectGrabbed(((NetworkBehaviour)gObject).NetworkObject.NetworkObjectId); ClientPlayer localPlayer = StatManager.Instance.LocalPlayer; if (localPlayer != null) { Utils.Log((LogLevel)32, $"Picked up {((NetworkBehaviour)gObject).NetworkObject.NetworkObjectId} in belt bag at {DateTime.UtcNow}"); localPlayer.ObtainedItems.TryAdd(((NetworkBehaviour)gObject).NetworkObject.NetworkObjectId, DateTime.UtcNow); } } } } public class DoorLockPatch { [HarmonyPostfix] [HarmonyPatch(typeof(DoorLock), "OpenOrCloseDoor")] private static void OpenOrCloseDoor(PlayerControllerB playerWhoTriggered, DoorLock __instance) { if (!((Object)(object)playerWhoTriggered != (Object)(object)GameNetworkManager.Instance.localPlayerController) && StatManager.Instance.IsOnMoon && (bool)typeof(DoorLock).GetField("isDoorOpened", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance)) { StatManager.Instance.LocalPlayer.DoorsOpened++; } } } public class PlayerControllerBPatch { [CompilerGenerated] private sealed class d__7 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(10f); <>1__state = 1; return true; case 1: <>1__state = -1; Utils.Log((LogLevel)16, "Connected with plugin version 1.12.1"); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static Vector3 lastPosition; [HarmonyPrefix] [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] public static void LateUpdate(PlayerControllerB __instance) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) if (!StatManager.Instance.IsOnMoon || __instance.isInElevator) { return; } ClientPlayer localPlayer = StatManager.Instance.LocalPlayer; if (!__instance.isPlayerControlled || __instance.isPlayerDead || localPlayer == null || localPlayer.SteamID != __instance.playerSteamId) { return; } _ = lastPosition; Vector3 val = lastPosition - ((Component)__instance).transform.localPosition; float magnitude = ((Vector3)(ref val)).magnitude; bool flag = (bool)typeof(PlayerControllerB).GetField("teleportingThisFrame", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance); if (!__instance.teleportedLastFrame && !flag) { bool flag2 = false; Object.FindObjectOfType(); if (__instance.jetpackControls) { GrabbableObject val2 = (GrabbableObject)(JetpackItem)((__instance.currentItemSlot == 50) ? __instance.ItemOnlySlot : __instance.ItemSlots[__instance.currentItemSlot]); if ((Object)(object)val2 != (Object)null) { flag2 = (bool)typeof(JetpackItem).GetField("jetpackActivated", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(val2); } } if (flag2) { localPlayer.DistanceJetpacked += magnitude; } else if (__instance.isSprinting) { localPlayer.DistanceSprinted += magnitude; } else if (__instance.isCrouching) { localPlayer.DistanceCrouched += magnitude; } else { localPlayer.DistanceWalked += magnitude; } localPlayer.DistanceTraveled += magnitude; } else if (__instance.teleportedLastFrame && __instance.isClimbingLadder) { localPlayer.DistanceLaddered += magnitude; localPlayer.DistanceTraveled += magnitude; } localPlayer.TotalStamina += __instance.sprintMeter; localPlayer.StaminaCounts++; if (Mathf.RoundToInt(Mathf.Clamp(__instance.carryWeight - 1f, 0f, 100f) * 105f) > 19 && __instance.isInsideFactory) { localPlayer.TimeSpentAbove19PoundsInside += Time.deltaTime; } if (__instance.drunkness > 0f) { localPlayer.TZPHighTime += Time.deltaTime; } bool flag3 = false; GrabbableObject[] itemSlots = __instance.ItemSlots; foreach (GrabbableObject val3 in itemSlots) { if ((Object)(object)val3 != (Object)null) { FlashlightItem val4 = (FlashlightItem)(object)((val3 is FlashlightItem) ? val3 : null); if (val4 != null && ((GrabbableObject)val4).isBeingUsed) { localPlayer.TotalFlashlightTime += Time.deltaTime; flag3 = true; break; } } } if (!flag3 && (Object)(object)__instance.ItemOnlySlot != (Object)null) { GrabbableObject itemOnlySlot = __instance.ItemOnlySlot; FlashlightItem val5 = (FlashlightItem)(object)((itemOnlySlot is FlashlightItem) ? itemOnlySlot : null); if (val5 != null && ((GrabbableObject)val5).isBeingUsed) { localPlayer.TotalFlashlightTime += Time.deltaTime; } } lastPosition = ((Component)__instance).transform.localPosition; } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerControllerB), "PlayerJump")] public static void PlayerJump(PlayerControllerB __instance) { if (StatManager.Instance.IsOnMoon) { ClientPlayer localPlayer = StatManager.Instance.LocalPlayer; if (localPlayer != null && localPlayer.SteamID == __instance.playerSteamId) { localPlayer.Jumps++; } } } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")] public static void DamagePlayer(int damageNumber, PlayerControllerB __instance) { if (StatManager.Instance.IsOnMoon && ((NetworkBehaviour)__instance).IsOwner && !__instance.isPlayerDead && __instance.AllowPlayerDeath()) { if (__instance.health - damageNumber <= 0 && !__instance.criticallyInjured && damageNumber < 50) { _ = __instance.health; } ClientPlayer localPlayer = StatManager.Instance.LocalPlayer; if (localPlayer != null && localPlayer.SteamID == __instance.playerSteamId) { Utils.Log((LogLevel)32, $"Damage Taken: {damageNumber}"); localPlayer.DamageTaken += (ushort)damageNumber; } } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] private static void KillPlayer(PlayerControllerB __instance) { if (!StatManager.Instance.IsOnMoon || !((NetworkBehaviour)__instance).IsOwner || !__instance.isPlayerDead) { return; } ClientPlayer localPlayer = StatManager.Instance.LocalPlayer; if (localPlayer != null && localPlayer.SteamID == __instance.playerSteamId) { if (!Environment.StackTrace.Contains("DamagePlayer")) { Utils.Log((LogLevel)32, $"Kill called from somewhere other than DamagePlayer. Adding health as damage {__instance.health}"); localPlayer.DamageTaken += (ushort)__instance.health; } StatManager.Instance.LocalPlayer.DiedTime = DateTime.UtcNow; } } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")] private static void GrabObjectClientRpc(bool grabValidated, NetworkObjectReference grabbedObject, PlayerControllerB __instance) { NetworkObject val = default(NetworkObject); if (StatManager.Instance.IsOnMoon && GameNetworkManager.Instance.localPlayerController.playerSteamId == __instance.playerSteamId && grabValidated && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null)) { StatManager.Instance.TrackObjectGrabbed(val.NetworkObjectId); ClientPlayer localPlayer = StatManager.Instance.LocalPlayer; if (localPlayer != null) { Utils.Log((LogLevel)32, $"Picked up {val.NetworkObjectId} at {DateTime.UtcNow}"); localPlayer.ObtainedItems.TryAdd(val.NetworkObjectId, DateTime.UtcNow); } } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] private static void ConnectClientToPlayerObject(PlayerControllerB __instance) { ((MonoBehaviour)__instance).StartCoroutine(OnJoin()); } [IteratorStateMachine(typeof(d__7))] private static IEnumerator OnJoin() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__7(0); } } public class StartOfRoundPatch { [HarmonyPatch(typeof(StartOfRound), "openingDoorsSequence")] [HarmonyPrefix] public static void openingDoorsSequence(StartOfRound __instance) { StatManager.Instance.StartRound(); } [HarmonyPatch(typeof(StartOfRound), "ShipHasLeft")] [HarmonyPrefix] public static void ShipHasLeft(StartOfRound __instance) { StatManager.Instance.EndRound(); } } public class VehicleControllerPatch { private static Dictionary m_LastCruiserPositions = new Dictionary(); [HarmonyPrefix] [HarmonyPatch(typeof(VehicleController), "LateUpdate")] public static void LateUpdate(VehicleController __instance) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_00a0: Unknown result type (might be due to invalid IL or missing references) float num = 0f; PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; ClientPlayer localPlayer = StatManager.Instance.LocalPlayer; if (m_LastCruiserPositions.ContainsKey(__instance)) { Vector3 val = m_LastCruiserPositions[__instance] - ((Component)__instance).transform.localPosition; num = ((Vector3)(ref val)).magnitude; } else { m_LastCruiserPositions.Add(__instance, ((Component)__instance).transform.localPosition); } if ((Object)(object)localPlayerController.physicsParent != (Object)null && (Object)(object)localPlayerController.physicsParent == (Object)(object)((Component)__instance).transform) { localPlayer.DistanceCruisered += num; } m_LastCruiserPositions[__instance] = ((Component)__instance).transform.localPosition; } } public class WalkieTalkiePatch { public static DateTime? StartUseTime; [HarmonyPrefix] [HarmonyPatch(typeof(WalkieTalkie), "SetLocalClientSpeaking")] private static void SetLocalClientSpeaking(bool speaking, WalkieTalkie __instance) { if ((Object)(object)((GrabbableObject)__instance).playerHeldBy != (Object)(object)GameNetworkManager.Instance.localPlayerController || !StatManager.Instance.IsOnMoon) { return; } if (speaking) { StartUseTime = DateTime.UtcNow; return; } if (!StartUseTime.HasValue) { StartUseTime = StatManager.Instance.LandedTime; } StatManager.Instance.LocalPlayer.TotalWalkieTime += DateTime.UtcNow - StartUseTime.Value; } } }