Decompiled source of CustomStatTracking v1.12.1

HighQuotaStatTracking.dll

Decompiled 5 days ago
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+f8e0d6d247ebb0f9f817b92e848fb1996e03cf88")]
[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<ulong, DateTime> ObtainedItems { get; set; } = new Dictionary<ulong, DateTime>();

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

		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 <OnJoin>d__7 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <OnJoin>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_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: 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<VehicleController>();
				if (__instance.jetpackControls && (Object)(object)__instance.ItemSlots[__instance.currentItemSlot] != (Object)null)
				{
					GrabbableObject obj = __instance.ItemSlots[__instance.currentItemSlot];
					JetpackItem val2 = (JetpackItem)(object)((obj is JetpackItem) ? obj : null);
					if (val2 != 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;
			}
			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;
						break;
					}
				}
			}
			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(<OnJoin>d__7))]
		private static IEnumerator OnJoin()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <OnJoin>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<VehicleController, Vector3> m_LastCruiserPositions = new Dictionary<VehicleController, Vector3>();

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