Decompiled source of GTFOStats v0.7.0

Danos-GTFOStats.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Agents;
using BepInEx;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Utils;
using Enemies;
using GTFOStats.Data;
using GTFOStats.Patches;
using GameData;
using GameEvent;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using LevelGeneration;
using Localization;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Danos-GTFOStats")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+b66383bdc5e660f814419b023c19dec99b331a38")]
[assembly: AssemblyProduct("Danos-GTFOStats")]
[assembly: AssemblyTitle("Danos-GTFOStats")]
[assembly: AssemblyVersion("1.0.0.0")]
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 GTFOStats
{
	[BepInPlugin("danos.GTFOStats", "GTFOStats", "0.7.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class DanosPlugin : BasePlugin
	{
		private static readonly HashSet<Type> AppliedPatches = new HashSet<Type>();

		private static readonly HashSet<string> AppliedDynamicPatches = new HashSet<string>();

		private static bool _additionalPatchesApplied = false;

		public static Harmony HarmonyInstance { get; private set; }

		public override void Load()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			HarmonyInstance = new Harmony("danos.GTFOStats");
			ApplyPatch(typeof(GameStateManagerPatch));
			Debug.Log(Object.op_Implicit("GTFOStats loaded and initial patches applied."));
		}

		public static void ApplyAdditionalPatches()
		{
			if (_additionalPatchesApplied)
			{
				Debug.Log(Object.op_Implicit("Additional patches already applied."));
				return;
			}
			ApplyPatch(typeof(GameStatePatch));
			ApplyPatch(typeof(DanosTerminalCommandPatch));
			ApplyPatch(typeof(DamagePatches));
			Debug.Log(Object.op_Implicit("GTFOStats is loaded!"));
			List<DanosPatchConfiguration> patchConfigurations = DanosPatchManager.GetPatchConfigurations();
			foreach (DanosPatchConfiguration item in patchConfigurations)
			{
				ApplyDynamicPatch(item);
			}
			_additionalPatchesApplied = true;
		}

		private static void ApplyDynamicPatch(DanosPatchConfiguration patchConfig)
		{
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Expected O, but got Unknown
			try
			{
				string text = $"{patchConfig.TargetClass}.{patchConfig.TargetMethod}.{patchConfig.PostfixMethod}";
				if (AppliedDynamicPatches.Contains(text))
				{
					Debug.Log(Object.op_Implicit("Patch already applied: " + text));
					return;
				}
				Type type = AccessTools.TypeByName(patchConfig.TargetClass);
				if (type == null)
				{
					Debug.Log(Object.op_Implicit("Target class '" + patchConfig.TargetClass + "' not found. Skipping patch."));
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(type, patchConfig.TargetMethod, (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					Debug.Log(Object.op_Implicit($"Target method '{patchConfig.TargetMethod}' not found in class '{patchConfig.TargetClass}'. Skipping patch."));
					return;
				}
				string[] array = patchConfig.PostfixMethod.Split('.');
				string name = array.Last();
				string text2 = string.Join('.', array.Take(array.Length - 1));
				Type type2 = Type.GetType(text2);
				if (type2 == null)
				{
					Debug.Log(Object.op_Implicit("Postfix class '" + text2 + "' not found. Skipping patch."));
					return;
				}
				MethodInfo method = type2.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Debug.Log(Object.op_Implicit("Postfix method '" + patchConfig.PostfixMethod + "' not found. Skipping patch."));
					return;
				}
				HarmonyInstance.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				AppliedDynamicPatches.Add(text);
				Debug.Log(Object.op_Implicit("Successfully patched " + patchConfig.TargetClass + "." + patchConfig.TargetMethod));
			}
			catch (Exception ex)
			{
				Debug.Log(Object.op_Implicit($"Failed to apply patch for {patchConfig.TargetClass}.{patchConfig.TargetMethod}: {ex.Message}"));
			}
		}

		private static void ApplyPatch(Type patchType)
		{
			if (!AppliedPatches.Contains(patchType))
			{
				HarmonyInstance.PatchAll(patchType);
				AppliedPatches.Add(patchType);
				Debug.Log(Object.op_Implicit("Patch applied: " + patchType.Name));
			}
			else
			{
				Debug.Log(Object.op_Implicit("Patch already applied: " + patchType.Name));
			}
		}
	}
}
namespace GTFOStats.Patches
{
	[HarmonyPatch]
	public class DamagePatches
	{
		[HarmonyPatch(typeof(EnemyAgent), "OnDead")]
		[HarmonyPrefix]
		public static bool OnDeadPrefix(EnemyAgent __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			if (DanosStaticStore.currentRunDownDataStore == null)
			{
				return true;
			}
			EnemyBalancingDataBlock enemyBalancingData = __instance.EnemyBalancingData;
			if (enemyBalancingData == null)
			{
				return true;
			}
			string name = ((GameDataBlockBase<EnemyBalancingDataBlock>)(object)enemyBalancingData).name;
			if (string.IsNullOrEmpty(name))
			{
				return true;
			}
			if (__instance.m_alive)
			{
				return true;
			}
			DanosStaticStore.currentRunDownDataStore.AddEnemyDeathCount(name);
			return true;
		}

		[HarmonyPatch(typeof(Dam_PlayerDamageBase), "OnIncomingDamage")]
		[HarmonyPrefix]
		public static bool OnIncomingDamagePrefix(Dam_PlayerDamageBase __instance, ref float damage, ref float originalDamage, ref Agent sourceAgent)
		{
			try
			{
				PlayerAgent owner = __instance.Owner;
				if ((Object)(object)owner == (Object)null)
				{
					return true;
				}
				string text = "Unknown";
				if ((Object)(object)sourceAgent != (Object)null)
				{
					if (((MemberInfo)((Object)sourceAgent).GetIl2CppType()).Name == typeof(PlayerAgent).Name)
					{
						text = "Player";
					}
					else if (((MemberInfo)((Object)sourceAgent).GetIl2CppType()).Name == typeof(LocalPlayerAgent).Name)
					{
						text = "Player";
					}
					else if (((MemberInfo)((Object)sourceAgent).GetIl2CppType()).Name == typeof(EnemyAgent).Name)
					{
						text = "Enemy";
						try
						{
							EnemyAgent val = ((Il2CppObjectBase)sourceAgent).Cast<EnemyAgent>();
							if ((Object)(object)val != (Object)null)
							{
								EnemyBalancingDataBlock enemyBalancingData = val.EnemyBalancingData;
								if (enemyBalancingData != null)
								{
									text = ((GameDataBlockBase<EnemyBalancingDataBlock>)(object)enemyBalancingData).name;
								}
							}
						}
						catch (Exception value)
						{
							Debug.LogError(Object.op_Implicit($"Error retrieving EnemyAgent details: {value}"));
						}
					}
					else
					{
						text = "Unknown";
					}
				}
				else
				{
					text = "Likely Projectile";
				}
				if ((Object)(object)owner != (Object)null)
				{
					DanosDamageInfoStore.UpdateDamage(owner, damage, sourceAgent, text);
				}
			}
			catch (Exception value2)
			{
				Debug.LogError(Object.op_Implicit($"Error in OnIncomingDamagePrefix: {value2}"));
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "ReceiveCommand")]
	internal class DanosTerminalCommandPatch
	{
		private static readonly HttpClient HttpClient = new HttpClient();

		private static readonly string ApiEndpoint = "https://localhost:7007/api/rundown/challenges";

		private static void Postfix(LG_ComputerTerminalCommandInterpreter __instance, TERM_Command cmd, string inputLine, string param1, string param2)
		{
			if (inputLine.Equals("challenges", StringComparison.OrdinalIgnoreCase))
			{
				__instance.ClearOutputQueueAndScreenBuffer();
				__instance.AddOutput((TerminalLineType)3, "<color=yellow>Loading Challenge Data...</color>", 1.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				DisplayBootupSequence(__instance);
				string steamIdForPlayer = GetSteamIdForPlayer();
				if (string.IsNullOrEmpty(steamIdForPlayer))
				{
					__instance.AddOutput((TerminalLineType)1, "<color=red>Unable to retrieve SteamID. Challenge data cannot be loaded.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				}
				else
				{
					__instance.AddOutput((TerminalLineType)1, "<color=red>No challenge data available for today.</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				}
			}
		}

		private static void DisplayBootupSequence(LG_ComputerTerminalCommandInterpreter interpreter)
		{
			interpreter.ClearOutputQueueAndScreenBuffer();
			interpreter.AddOutput((TerminalLineType)0, "   _____ _______ ______ ____   _____ _        _       ", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "  / ____|__   __|  ____/ __ \\ / ____| |      | |      ", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, " | |  __   | |  | |__ | |  | | (___ | |_ __ _| |_ ___ ", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, " | | |_ |  | |  |  __|| |  | |\\___ \\| __/ _` | __/ __|", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, " | |__| |  | |  | |   | |__| |____) | || (_| | |_\\__ \\", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "  \\_____|  |_|  |_|    \\____/|_____/ \\__\\__,_|\\__|___/", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "                                                     ", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "                                                     ", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "<color=green>Initializing GTFOStats Subsystem...</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "Connecting to SplitStats Database...", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "Authenticating with SplitStats Servers...", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "System Diagnostics: <color=green>OK</color>", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "Telemetry Systems: <color=yellow>ACTIVE</color>", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "Collecting Initial Player Data...", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "<color=green>GTFOStats Subsystem Online</color>", 1f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "<color=yellow>View your stats online at:</color>", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)5, "https://gtfo.splitstats.io", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
			interpreter.AddOutput((TerminalLineType)0, "------------------------------------", 0.3f, (TerminalSoundType)0, (TerminalSoundType)0);
		}

		private static async Task<DanosChallengeResponse?> FetchChallengesAsync(string steamId)
		{
			try
			{
				string requestUrl = ApiEndpoint + "?steamId=" + Uri.EscapeDataString(steamId);
				Task<HttpResponseMessage> request = HttpClient.GetAsync(requestUrl);
				if (await Task.WhenAny(request, Task.Delay(3000)) == request)
				{
					HttpResponseMessage response = await request;
					if (response.IsSuccessStatusCode)
					{
						string jsonString = await response.Content.ReadAsStringAsync();
						Console.WriteLine(jsonString);
						return JsonSerializer.Deserialize<DanosChallengeResponse>(jsonString);
					}
					Console.WriteLine($"Error fetching challenges: {response.StatusCode}");
				}
			}
			catch (Exception ex2)
			{
				Exception ex = ex2;
				Console.WriteLine("Error fetching challenges: " + ex.Message);
			}
			return null;
		}

		private static void DisplayUserInfo(LG_ComputerTerminalCommandInterpreter terminal, DanosChallengeResponse challenges)
		{
			TimeSpan timeSpan = DateTime.Now - challenges.FirstMatchDate;
			terminal.AddOutput((TerminalLineType)0, "<color=green>--- Player Info ---</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
			terminal.AddOutput((TerminalLineType)0, $"<color=yellow>Current XP: {challenges.CurrentXp}</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
			terminal.AddOutput((TerminalLineType)0, $"<color=yellow>Service Length: {timeSpan.Days}d {timeSpan.Hours}h</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
			terminal.AddOutput((TerminalLineType)0, "", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
		}

		private static void DisplayChallenges(LG_ComputerTerminalCommandInterpreter terminal, DanosChallengeResponse challenges)
		{
			if (challenges.DailyChallenges.Count > 0)
			{
				terminal.AddOutput((TerminalLineType)0, "<color=green>--- Today's Daily Challenges ---</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				foreach (DanosChallengeData dailyChallenge in challenges.DailyChallenges)
				{
					terminal.AddOutput((TerminalLineType)0, "<color=orange>" + dailyChallenge.Title + "</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
					terminal.AddOutput((TerminalLineType)0, GetProgressBar(dailyChallenge.Progress, dailyChallenge.Goal), 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
					terminal.AddOutput((TerminalLineType)0, $"Progress: {dailyChallenge.Progress}/{dailyChallenge.Goal}", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
					terminal.AddOutput((TerminalLineType)0, $"<color=yellow>XP Reward: {dailyChallenge.XpReward} XP</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
					terminal.AddOutput((TerminalLineType)0, $"<color=yellow>Time Remaining: {dailyChallenge.TimeRemaining.Days}d {dailyChallenge.TimeRemaining.Hours}h</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
					terminal.AddOutput((TerminalLineType)0, "", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				}
			}
			if (challenges.WeeklyChallenges.Count <= 0)
			{
				return;
			}
			terminal.AddOutput((TerminalLineType)0, "<color=green>--- Weekly Challenges ---</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
			foreach (DanosChallengeData weeklyChallenge in challenges.WeeklyChallenges)
			{
				terminal.AddOutput((TerminalLineType)0, "<color=orange>" + weeklyChallenge.Title + "</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				terminal.AddOutput((TerminalLineType)0, GetProgressBar(weeklyChallenge.Progress, weeklyChallenge.Goal), 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				terminal.AddOutput((TerminalLineType)0, $"Progress: {weeklyChallenge.Progress}/{weeklyChallenge.Goal}", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				terminal.AddOutput((TerminalLineType)0, $"<color=yellow>XP Reward: {weeklyChallenge.XpReward} XP</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				terminal.AddOutput((TerminalLineType)0, $"<color=yellow>Time Remaining: {weeklyChallenge.TimeRemaining.Days}d {weeklyChallenge.TimeRemaining.Hours}h</color>", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
				terminal.AddOutput((TerminalLineType)0, "", 0.5f, (TerminalSoundType)0, (TerminalSoundType)0);
			}
		}

		private static string GetProgressBar(int current, int total)
		{
			int num = 20;
			int num2 = (int)((double)current / (double)total * (double)num);
			string text = new string('=', num2);
			string text2 = new string('-', num - num2);
			return "[" + text + text2 + "]";
		}

		private static string GetSteamIdForPlayer()
		{
			long localPlayerSteamID = GameStatePatch.GetLocalPlayerSteamID();
			if (localPlayerSteamID <= 0)
			{
				return null;
			}
			return localPlayerSteamID.ToString();
		}
	}
	[HarmonyPatch]
	public class GameStateManagerPatch
	{
		public static PolicyVersion policy = new PolicyVersion();

		[HarmonyPatch(typeof(GameStateManager), "ChangeState")]
		[HarmonyPrefix]
		public static bool ChangeStatePrefix(eGameStateName nextState)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Invalid comparison between Unknown and I4
			try
			{
				policy = GetPolicy().Result;
				if (HasUserAcceptedPolicy(policy.Version))
				{
					Debug.Log(Object.op_Implicit("User has already accepted the current policy version."));
					DanosPlugin.ApplyAdditionalPatches();
					return true;
				}
			}
			catch (Exception ex)
			{
				Debug.Log(Object.op_Implicit("Error getting policy: " + ex.Message));
			}
			if ((int)nextState == 4)
			{
				ShowPopup(delegate
				{
					Debug.Log(Object.op_Implicit("User accepted GTFOStats terms."));
					SaveUserResponse(accepted: true, policy.Version);
					DanosPlugin.ApplyAdditionalPatches();
				}, delegate
				{
					Debug.Log(Object.op_Implicit("User declined GTFOStats terms. Closing the game."));
					Application.Quit();
				});
				return true;
			}
			return true;
		}

		private static bool HasUserAcceptedPolicy(string policyVersion)
		{
			try
			{
				string location = Assembly.GetExecutingAssembly().Location;
				string directoryName = Path.GetDirectoryName(location);
				string path = Path.Combine(directoryName, "GTFOStatsPrivacyResponse.txt");
				if (!File.Exists(path))
				{
					return false;
				}
				string[] array = File.ReadAllLines(path);
				string[] array2 = array;
				foreach (string text in array2)
				{
					if (text.Contains("Policy Version: " + policyVersion))
					{
						return true;
					}
				}
			}
			catch (Exception ex)
			{
				Debug.Log(Object.op_Implicit("Error checking user response: " + ex.Message));
			}
			return false;
		}

		private static void SaveUserResponse(bool accepted, string policyVersion)
		{
			try
			{
				string location = Assembly.GetExecutingAssembly().Location;
				string directoryName = Path.GetDirectoryName(location);
				string text = Path.Combine(directoryName, "GTFOStatsPrivacyResponse.txt");
				string value = (accepted ? "Accepted" : "Declined");
				string contents = $"User Response: {value}\nPolicy Version: {policyVersion}\nDate: {DateTime.Now}";
				File.WriteAllText(text, contents);
				Debug.Log(Object.op_Implicit("User response saved to: " + text));
			}
			catch (Exception ex)
			{
				Debug.Log(Object.op_Implicit("Error saving user response: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(GameStateManager), "Update")]
		[HarmonyPrefix]
		public static void UpdatePostfix()
		{
			GlobalInputManager.Update();
		}

		public static void ShowPopup(Action onAccept, Action onDecline)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			Action onAccept2 = onAccept;
			Action onDecline2 = onDecline;
			if (!((Object)(object)GameObject.Find("GTFOStatsPopupCanvas") != (Object)null))
			{
				GameObject popupCanvas = new GameObject("GTFOStatsPopupCanvas");
				Canvas val = popupCanvas.AddComponent<Canvas>();
				val.renderMode = (RenderMode)0;
				CanvasScaler val2 = popupCanvas.AddComponent<CanvasScaler>();
				val2.uiScaleMode = (ScaleMode)1;
				popupCanvas.AddComponent<GraphicRaycaster>();
				GameObject val3 = new GameObject("Panel");
				RectTransform val4 = val3.AddComponent<RectTransform>();
				val4.sizeDelta = new Vector2(500f, 400f);
				((Transform)val4).SetParent(popupCanvas.transform, false);
				Image val5 = val3.AddComponent<Image>();
				((Graphic)val5).color = HexToColor("#181a22");
				CreateText(val3, "GTFOStats", new Vector2(0f, 150f), 36, (TextAnchor)1, "#6ac4a7");
				string message = "Welcome to GTFOStats! By using this mod, you agree to the privacy policy at https://gtfo.splitstats.io/privacypolicy.\n\nGame stats will be collected and uploaded during gameplay. Your response to the policy will be saved in the mod folder until you uninstall the mod or the policy changes.\n\nManage or delete your data using tools on our website. Decline to close the game and uninstall the mod.";
				string message2 = $"We do not store contact information, so we cannot directly inform you of any changes, however this prompt will popup any time we make any.\n\nVersion: {policy.Version}\nLast Updated: {policy.LastUpdated.ToShortDateString()}\nChanges: {policy.DescriptionOfChanges}\nLast Updated: {policy.LastUpdatedDaysAgo}.";
				CreateText(val3, message, new Vector2(0f, 75f), 8, (TextAnchor)4);
				CreateText(val3, message2, new Vector2(0f, -25f), 5, (TextAnchor)4);
				CreateText(val3, "[F5] Open Privacy Policy", new Vector2(0f, -60f), 24, (TextAnchor)4, "#6ac4a7");
				CreateText(val3, "[F6] Accept", new Vector2(-100f, -120f), 24, (TextAnchor)4, "#6ac4a7");
				CreateText(val3, "[F7] Decline", new Vector2(100f, -120f), 24, (TextAnchor)4, "#FF6A6A");
				GlobalInputManager.ListenForKeys((KeyCode)286, delegate
				{
					Application.OpenURL("https://gtfo.splitstats.io/privacypolicy");
				});
				GlobalInputManager.ListenForKeys((KeyCode)287, delegate
				{
					Object.Destroy((Object)(object)popupCanvas);
					GlobalInputManager.StopListeningForKeys((KeyCode)286);
					GlobalInputManager.StopListeningForKeys((KeyCode)287);
					GlobalInputManager.StopListeningForKeys((KeyCode)288);
					onAccept2?.Invoke();
				});
				GlobalInputManager.ListenForKeys((KeyCode)288, delegate
				{
					Object.Destroy((Object)(object)popupCanvas);
					GlobalInputManager.StopListeningForKeys((KeyCode)286);
					GlobalInputManager.StopListeningForKeys((KeyCode)287);
					GlobalInputManager.StopListeningForKeys((KeyCode)288);
					onDecline2?.Invoke();
				});
			}
		}

		private static async Task<PolicyVersion> GetPolicy()
		{
			PolicyVersion policy = new PolicyVersion();
			HttpClient client = new HttpClient();
			HttpResponseMessage response = await client.GetAsync("https://gtfo.splitstats.io/api/Privacy/current");
			if (response.IsSuccessStatusCode)
			{
				policy = await response.Content.ReadFromJsonAsync<PolicyVersion>();
				if (policy == null)
				{
					return new PolicyVersion();
				}
			}
			return policy;
		}

		private static void CreateText(GameObject parent, string message, Vector2 position, int fontSize = 20, TextAnchor alignment = 4, string hexColor = "#FFFFFF", Color? backgroundColor = null)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("TextElement");
			Text val2 = val.AddComponent<Text>();
			val2.text = message;
			val2.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			val2.fontSize = fontSize;
			val2.alignment = alignment;
			((Graphic)val2).color = HexToColor(hexColor);
			RectTransform component = ((Component)val2).GetComponent<RectTransform>();
			component.sizeDelta = new Vector2(460f, 100f);
			component.anchoredPosition = position;
			((Transform)component).SetParent(parent.transform, false);
			if (backgroundColor.HasValue)
			{
				GameObject val3 = new GameObject("Background");
				Image val4 = val3.AddComponent<Image>();
				((Graphic)val4).color = backgroundColor.Value;
				RectTransform component2 = val3.GetComponent<RectTransform>();
				component2.sizeDelta = new Vector2(220f, 60f);
				component2.anchoredPosition = position;
				((Transform)component2).SetParent(parent.transform, false);
				((Component)val2).transform.SetParent(val3.transform, false);
			}
		}

		private static Color HexToColor(string hex)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Color result = default(Color);
			if (ColorUtility.TryParseHtmlString(hex, ref result))
			{
				return result;
			}
			return Color.white;
		}
	}
	public static class GlobalInputManager
	{
		private static readonly Dictionary<KeyCode, Action> keyActions = new Dictionary<KeyCode, Action>();

		public static void ListenForKeys(KeyCode key, Action action)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (!keyActions.ContainsKey(key))
			{
				keyActions[key] = action;
			}
		}

		public static void StopListeningForKeys(KeyCode key)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (keyActions.ContainsKey(key))
			{
				keyActions.Remove(key);
			}
		}

		public static void StopAllListening()
		{
			keyActions.Clear();
		}

		public static void Update()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (keyActions.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<KeyCode, Action> keyAction in keyActions)
			{
				if (Input.GetKeyDown(keyAction.Key))
				{
					keyAction.Value?.Invoke();
				}
			}
		}
	}
	[HarmonyPatch]
	public static class GameStatePatch
	{
		private static Coroutine positionCollectorCoroutine;

		[HarmonyPatch(typeof(GameEventManager), "PostEvent", new Type[]
		{
			typeof(eGameEvent),
			typeof(PlayerAgent),
			typeof(float),
			typeof(string),
			typeof(Dictionary<string, string>)
		})]
		[HarmonyPrefix]
		public static void Patch_PostEvent_Overload2(eGameEvent e, PlayerAgent player, float floatVal, string stringVal, Dictionary<string, string> customAnalyticsPayload)
		{
			string text = ((object)(eGameEvent)(ref e)).ToString();
			if (text == "gs_StopElevatorRide")
			{
				Console.WriteLine("Elevator ride ended");
				ResetRunDownData();
				InitializeRunDownData();
				StartPositionCollector();
			}
			else if (text == "gs_ExpeditionFail" || text == "gs_ExpeditionSuccess")
			{
				Console.WriteLine("Expedition ended");
				ExportRunDownData(text);
				StopPositionCollector();
			}
			else if (text == "gs_ExpeditionAbort")
			{
				Console.WriteLine("Expedition Aborted");
				ExportRunDownData(text);
				StopPositionCollector();
			}
			if (DanosStaticStore.currentRunDownDataStore != null)
			{
				switch (text)
				{
				case "player_downed":
					DanosStaticStore.currentRunDownDataStore.AddPlayerDownData((long)player.Owner.Lookup, player);
					break;
				case "player_reload":
					DanosStaticStore.currentRunDownDataStore.AddPlayerReloadData((long)player.Owner.Lookup);
					break;
				case "player_apply_medikit":
					DanosStaticStore.currentRunDownDataStore.AddPlayerHealthPackUsed((long)player.Owner.Lookup);
					break;
				case "player_apply_ammokit":
					DanosStaticStore.currentRunDownDataStore.AddPlayerAmmoPackUsed((long)player.Owner.Lookup);
					break;
				case "player_apply_disinfection":
					DanosStaticStore.currentRunDownDataStore.AddPlayerDisinfectionUsed((long)player.Owner.Lookup);
					break;
				case "player_pickup_artifact":
					DanosStaticStore.currentRunDownDataStore.AddPlayerArtifactPickup((long)player.Owner.Lookup);
					break;
				case "player_place_tripmine":
					DanosStaticStore.currentRunDownDataStore.AddPlayerTripMinePlaced((long)player.Owner.Lookup);
					break;
				case "player_pickup_keycard":
					DanosStaticStore.currentRunDownDataStore.AddPlayerKeyCardPickup((long)player.Owner.Lookup);
					break;
				case "player_hacking_success":
					DanosStaticStore.currentRunDownDataStore.AddPlayerHackingSuccess((long)player.Owner.Lookup);
					break;
				case "bioscan_start":
					DanosStaticStore.currentRunDownDataStore.IncrementBioscanStart();
					break;
				case "scout_enemy_dead":
					DanosStaticStore.currentRunDownDataStore.IncrementScoutEnemiesDead();
					break;
				case "enemy_dead":
					DanosStaticStore.currentRunDownDataStore.IncrementEnemiesDead();
					break;
				case "enemy_wave_spawned":
					DanosStaticStore.currentRunDownDataStore.IncrementEnemyWavesSpawned();
					break;
				case "scout_enemy_found_player":
					DanosStaticStore.currentRunDownDataStore.IncrementScoutEnemiesFoundPlayer();
					break;
				case "hibernating_enemy_dead":
					DanosStaticStore.currentRunDownDataStore.IncrementHibernatingEnemiesDead();
					break;
				case "hibernating_enemy_wakeup":
					DanosStaticStore.currentRunDownDataStore.IncrementHibernatingEnemiesWokeUp();
					break;
				case "enemy_dead_from_melee":
					DanosStaticStore.currentRunDownDataStore.IncrementEnemiesDeadFromMelee();
					break;
				case "enemy_scout_dead_from_melee":
					DanosStaticStore.currentRunDownDataStore.IncrementScoutEnemiesDeadFromMelee();
					break;
				}
			}
		}

		private static void StartPositionCollector()
		{
			if (positionCollectorCoroutine == null)
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				positionCollectorCoroutine = ((localPlayerAgent != null) ? MonoBehaviourExtensions.StartCoroutine((MonoBehaviour)(object)localPlayerAgent, CollectPositionsCoroutine()) : null);
				if (positionCollectorCoroutine == null)
				{
					Console.WriteLine("Failed to start position collector coroutine.");
				}
			}
		}

		private static void CollectPlayerPositions()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<PlayerAgent> playerAgentsInLevel = PlayerManager.PlayerAgentsInLevel;
				long st = DanosStaticStore.currentRunDownDataStore.st;
				long num = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
				long timestamp = num - st;
				Enumerator<PlayerAgent> enumerator = playerAgentsInLevel.GetEnumerator();
				while (enumerator.MoveNext())
				{
					PlayerAgent current = enumerator.Current;
					if (!((Object)(object)current == (Object)null) && ((Agent)current).m_replicator != null)
					{
						Vector3 position = ((Component)current).transform.position;
						ulong lookup = ((Agent)current).m_replicator.OwningPlayer.Lookup;
						DanosPositionalDataTransfer dataTransfer = new DanosPositionalDataTransfer
						{
							x = position.x,
							z = position.z,
							Timestamp = timestamp,
							sid = (long)lookup,
							Name = current.PlayerName
						};
						DanosStaticStore.currentRunDownDataStore.AddPositionalData(dataTransfer);
					}
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine("Error collecting player positions: " + ex.Message);
			}
		}

		private static IEnumerator CollectPositionsCoroutine()
		{
			while (true)
			{
				CollectPlayerPositions();
				yield return (object)new WaitForSeconds(3f);
			}
		}

		private static void StopPositionCollector()
		{
			if (positionCollectorCoroutine != null)
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				if (localPlayerAgent != null)
				{
					((MonoBehaviour)localPlayerAgent).StopCoroutine(positionCollectorCoroutine);
				}
				positionCollectorCoroutine = null;
			}
		}

		private static void ExportRunDownData(string reason)
		{
			try
			{
				if (DanosStaticStore.currentRunDownDataStore == null)
				{
					Debug.LogError(Object.op_Implicit("No rundown data store to export."));
					return;
				}
				JsonSerializerOptions options = new JsonSerializerOptions
				{
					WriteIndented = true,
					Converters = { (JsonConverter)new OneDecimalJsonConverter() }
				};
				DanosStaticStore.currentRunDownDataStore.et = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
				DanosStaticStore.currentRunDownDataStore.rer = reason;
				DanosStaticStore.currentRunDownDataStore.wasHost = SNet.IsMaster;
				List<PlayerAgent> playerAgentsInLevel = PlayerManager.PlayerAgentsInLevel;
				Enumerator<PlayerAgent> enumerator = playerAgentsInLevel.GetEnumerator();
				while (enumerator.MoveNext())
				{
					PlayerAgent current = enumerator.Current;
					if (!((Object)(object)current == (Object)null) && ((Agent)current).m_replicator != null)
					{
						DanosStaticStore.currentRunDownDataStore.AddPlayerToSummary((long)((Agent)current).m_replicator.OwningPlayer.Lookup, current);
					}
				}
				DanosRunDownDataStore value = DanosAnonymization.AnonymizeRundownStore(DanosStaticStore.currentRunDownDataStore);
				string json = JsonSerializer.Serialize(value, options);
				List<string> list = new List<string>();
				foreach (Func<string> jsonContributor in DanosStaticStore.JsonContributors)
				{
					try
					{
						string text = jsonContributor();
						if (!string.IsNullOrEmpty(text))
						{
							list.Add(text);
						}
					}
					catch (Exception ex)
					{
						Console.WriteLine("Error invoking JSON contributor: " + ex.Message);
					}
				}
				Dictionary<string, object> dictionary = JsonSerializer.Deserialize<Dictionary<string, object>>(json, options);
				foreach (string item in list)
				{
					Dictionary<string, object> dictionary2 = JsonSerializer.Deserialize<Dictionary<string, object>>(item, options);
					if (dictionary2 == null)
					{
						continue;
					}
					foreach (KeyValuePair<string, object> item2 in dictionary2)
					{
						dictionary[item2.Key] = item2.Value;
					}
				}
				string text2 = JsonSerializer.Serialize(dictionary, options);
				string text3 = Path.Combine(Application.persistentDataPath, "RunDownData.json");
				File.WriteAllText(text3, text2);
				Console.WriteLine("Rundown data exported to " + text3);
				PostDataToAPI(text2).Wait();
			}
			catch (Exception ex2)
			{
				Console.WriteLine("Error exporting rundown data: " + ex2.Message);
			}
		}

		private static async Task PostDataToAPI(string json)
		{
			try
			{
				ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13;
				using HttpClient client = new HttpClient();
				client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
				HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
				HttpResponseMessage response = await client.PostAsync("https://gtfoapi.splitstats.io/api/rundown/upload", content);
				if (response.IsSuccessStatusCode)
				{
					Console.WriteLine("Data posted to API successfully.");
					return;
				}
				Console.WriteLine($"Error posting data to API: {response.StatusCode}");
			}
			catch (Exception ex2)
			{
				Exception ex = ex2;
				Console.WriteLine("Error posting data to API: " + ex.Message);
				if (ex.InnerException != null)
				{
					Console.WriteLine("Inner Exception: " + ex.InnerException.Message);
				}
			}
		}

		private static void InitializeRunDownData()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				DanosRunDownDataStore danosRunDownDataStore2 = (DanosStaticStore.currentRunDownDataStore = new DanosRunDownDataStore
				{
					st = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
					msid = GetLocalPlayerSteamID(),
					mv = "0.7.0"
				});
				string en = string.Empty;
				string text = string.Empty;
				string rsg = string.Empty;
				eRundownTier val;
				try
				{
					pActiveExpedition activeExpeditionData = RundownManager.GetActiveExpeditionData();
					if (activeExpeditionData == null)
					{
						throw new Exception("Active expedition data is null");
					}
					val = activeExpeditionData.tier;
					en = ((object)(eRundownTier)(ref val)).ToString();
					text = activeExpeditionData.expeditionIndex.ToString();
					rsg = activeExpeditionData.sessionGUID.m_data.ToString();
				}
				catch (Exception ex)
				{
					Debug.LogError(Object.op_Implicit("Error fetching expedition data: " + ex.Message));
				}
				DanosExtraRundownData extraData = new DanosExtraRundownData();
				string rid = string.Empty;
				try
				{
					string storyTitle = string.Empty;
					string otherTitle = string.Empty;
					string storyDescription = string.Empty;
					uint num = default(uint);
					if (RundownManager.TryGetIdFromLocalRundownKey(RundownManager.ActiveRundownKey, ref num))
					{
						RundownDataBlock block = GameDataBlockBase<RundownDataBlock>.GetBlock(num);
						if (((block != null) ? block.StorytellingData : null) != null)
						{
							storyTitle = LocalizedText.op_Implicit(block.StorytellingData.Title);
							storyDescription = LocalizedText.op_Implicit(block.StorytellingData.SurfaceDescription);
							otherTitle = LocalizedText.op_Implicit(block.StorytellingData.ExternalExpTitle);
						}
					}
					ExpeditionInTierData activeExpedition = RundownManager.ActiveExpedition;
					DescriptiveData descriptive = activeExpedition.Descriptive;
					string text2 = descriptive.Prefix + ((!descriptive.SkipExpNumberInName) ? (text + 1).ToString() : "");
					string rundownName = descriptive.PublicName + (descriptive.IsExtraExpedition ? "://EXT" : "");
					DanosExtraRundownData obj = new DanosExtraRundownData
					{
						rundownKey = RundownManager.ActiveRundownKey,
						rundownName = rundownName,
						otherTitle = otherTitle,
						rundownprefix = text2,
						storyDescription = storyDescription,
						storyTitle = storyTitle,
						devInfo = descriptive.DevInfo
					};
					val = descriptive.CustomMatchmakingTier;
					obj.matchmakingtier = ((object)(eRundownTier)(ref val)).ToString();
					obj.desc2 = LocalizedText.op_Implicit(descriptive.ExpeditionDescription);
					obj.depth = descriptive.ExpeditionDepth.ToString();
					extraData = obj;
					rid = text2;
				}
				catch (Exception ex2)
				{
					Debug.LogError(Object.op_Implicit("Error initializing extra rundown data: " + ex2.Message));
				}
				danosRunDownDataStore2.rid = rid;
				danosRunDownDataStore2.en = en;
				danosRunDownDataStore2.ei = text;
				danosRunDownDataStore2.rsg = rsg;
				danosRunDownDataStore2.extraData = extraData;
				DanosStaticStore.currentRunDownDataStore = danosRunDownDataStore2;
			}
			catch (Exception ex3)
			{
				Debug.LogError(Object.op_Implicit("Error initializing DanosRunDownDataStore: " + ex3.Message));
			}
		}

		private static void LogEventData(string eventName, PlayerAgent player, string customString, float floatVal = 0f, Dictionary<string, string> customAnalyticsPayload = null)
		{
			try
			{
				if (customAnalyticsPayload == null)
				{
					customAnalyticsPayload = new Dictionary<string, string>();
				}
				Dictionary<string, string> dictionary = new Dictionary<string, string>();
				Enumerator<string, string> enumerator = customAnalyticsPayload.GetEnumerator();
				while (enumerator.MoveNext())
				{
					KeyValuePair<string, string> current = enumerator.Current;
					if (current.Key != null && current.Value != null && !dictionary.ContainsKey(current.Key))
					{
						dictionary[current.Key] = current.Value;
					}
				}
				DanosGameEvent value = new DanosGameEvent
				{
					eventName = eventName,
					playerInfo = (((player != null) ? player.PlayerName : null) ?? "No Player"),
					customString = (customString ?? "No String")
				};
				string text = JsonSerializer.Serialize(value);
				Console.WriteLine("Event Data: " + text);
			}
			catch (Exception ex)
			{
				Debug.LogError(Object.op_Implicit("Error logging event data: " + ex.Message));
			}
		}

		public static long GetLocalPlayerSteamID()
		{
			try
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				if ((Object)(object)localPlayerAgent == (Object)null)
				{
					return -1L;
				}
				if (((Agent)localPlayerAgent).m_replicator == null)
				{
					return -2L;
				}
				if ((Object)(object)((Agent)localPlayerAgent).m_replicator.OwningPlayer == (Object)null)
				{
					return -3L;
				}
				ulong? obj;
				if (localPlayerAgent == null)
				{
					obj = null;
				}
				else
				{
					SNet_Replicator replicator = ((Agent)localPlayerAgent).m_replicator;
					obj = ((replicator != null) ? new ulong?(replicator.OwningPlayer.Lookup) : null);
				}
				ulong? num = obj;
				return (long)num.GetValueOrDefault();
			}
			catch
			{
				return -4L;
			}
		}

		public static void ResetRunDownData()
		{
			DanosStaticStore.currentRunDownDataStore = new DanosRunDownDataStore();
		}
	}
	public class DanosGameEvent
	{
		public string eventName { get; set; }

		public string playerInfo { get; set; }

		public string customString { get; set; }
	}
	public static class XpHandlerPatches
	{
		private static PropertyInfo xpGainProperty;

		private static PropertyInfo debuffXpProperty;

		public static void AddXpPostfix(object xpData, Vector3 xpTextPosition, bool forceDebuffXp, string xpPopupColor)
		{
			try
			{
				if (xpGainProperty == null)
				{
					xpGainProperty = xpData.GetType().GetProperty("XpGain");
				}
				if (debuffXpProperty == null)
				{
					debuffXpProperty = xpData.GetType().GetProperty("DebuffXp");
				}
				uint xp = ((xpGainProperty != null) ? ((uint)xpGainProperty.GetValue(xpData)) : 0u);
				uint num = ((debuffXpProperty != null) ? ((uint)debuffXpProperty.GetValue(xpData)) : 0u);
				if (DanosStaticStore.currentRunDownDataStore != null)
				{
					DanosStaticStore.currentRunDownDataStore.AddXP(xp);
				}
			}
			catch (Exception)
			{
			}
		}
	}
}
namespace GTFOStats.Data
{
	public static class DanosAnonymization
	{
		public static ulong MinSteamId64 = 76561197960265728uL;

		public static ulong MaxSteamId64 = 76561202255233023uL;

		public static bool ValidateSteamId64(ulong steamId)
		{
			return steamId >= MinSteamId64 && steamId <= MaxSteamId64 && steamId.ToString().Length == 17;
		}

		public static DanosRunDownDataStore AnonymizeRundownStore(DanosRunDownDataStore store)
		{
			DanosRunDownDataStore store2 = store;
			DanosRunDownDataStore danosRunDownDataStore = new DanosRunDownDataStore
			{
				wasHost = store2.wasHost,
				mv = store2.mv,
				rer = store2.rer,
				st = store2.st,
				et = store2.et,
				rid = store2.rid,
				en = store2.en,
				ei = store2.ei,
				rsg = store2.rsg,
				msid = store2.msid,
				xp = store2.xp,
				bioscanStarts = store2.bioscanStarts,
				scoutEnemiesDead = store2.scoutEnemiesDead,
				enemiesDead = store2.enemiesDead,
				enemyWavesSpawned = store2.enemyWavesSpawned,
				scoutEnemiesFoundPlayer = store2.scoutEnemiesFoundPlayer,
				hibernatingEnemiesDead = store2.hibernatingEnemiesDead,
				hibernatingEnemiesWokeUp = store2.hibernatingEnemiesWokeUp,
				enemiesDeadFromMelee = store2.enemiesDeadFromMelee,
				scoutEnemiesDeadFromMelee = store2.scoutEnemiesDeadFromMelee,
				edc = new Dictionary<string, int>(store2.edc),
				extraData = store2.extraData
			};
			Dictionary<long, long> steamIdMapping = new Dictionary<long, long>();
			long nextSteamIndex = 10L;
			List<long> list = (from id in store2.pl.Keys
				where !ValidateSteamId64((ulong)id)
				orderby id
				select id).ToList();
			List<long> list2 = (from id in store2.pl.Keys
				where ValidateSteamId64((ulong)id)
				orderby id
				select id).ToList();
			foreach (long item in list)
			{
				danosRunDownDataStore.pl[item] = store2.pl[item];
				if (store2.pd.ContainsKey(item))
				{
					danosRunDownDataStore.pd[item] = store2.pd[item];
				}
				if (store2.sd.ContainsKey(item))
				{
					danosRunDownDataStore.sd[item] = store2.sd[item];
				}
				if (store2.ds.ContainsKey(item))
				{
					danosRunDownDataStore.ds[item] = store2.ds[item];
				}
			}
			foreach (long item2 in list2)
			{
				long key = GetAnonymizedId(item2);
				danosRunDownDataStore.pl[key] = store2.pl[item2];
				danosRunDownDataStore.pl[key] = "Anon " + key;
				if (store2.pd.ContainsKey(item2))
				{
					danosRunDownDataStore.pd[key] = store2.pd[item2];
				}
				if (store2.sd.ContainsKey(item2))
				{
					danosRunDownDataStore.sd[key] = store2.sd[item2];
				}
				if (store2.ds.ContainsKey(item2))
				{
					danosRunDownDataStore.ds[key] = store2.ds[item2];
				}
			}
			return danosRunDownDataStore;
			long GetAnonymizedId(long steamId)
			{
				if (steamId == store2.msid || !ValidateSteamId64((ulong)steamId))
				{
					return steamId;
				}
				if (!steamIdMapping.ContainsKey(steamId))
				{
					steamIdMapping[steamId] = nextSteamIndex++;
				}
				return steamIdMapping[steamId];
			}
		}
	}
	public class DanosChallengeData
	{
		public string Title { get; set; }

		public int Progress { get; set; }

		public int Goal { get; set; }

		public int XpReward { get; set; }

		public TimeSpan TimeRemaining { get; set; }
	}
	public class DanosChallengeResponse
	{
		public List<DanosChallengeData> DailyChallenges { get; set; } = new List<DanosChallengeData>();


		public List<DanosChallengeData> WeeklyChallenges { get; set; } = new List<DanosChallengeData>();


		public int CurrentXp { get; set; }

		public DateTime FirstMatchDate { get; set; }
	}
	public class DanosDamageInfoStore
	{
		public class DamageRecord
		{
			public float Damage { get; set; }

			[JsonIgnore]
			public PlayerAgent DamagedAgent { get; set; }

			[JsonIgnore]
			public Agent SourceAgent { get; set; }

			public string SourceType { get; set; }

			public DateTime Timestamp { get; set; }
		}

		public static Dictionary<long, DamageRecord> _lastDamageByPlayer = new Dictionary<long, DamageRecord>();

		public static void UpdateDamage(PlayerAgent damagedAgent, float damage, Agent sourceAgent, string sourceType)
		{
			if (!((Object)(object)damagedAgent == (Object)null) && ((Agent)damagedAgent).m_replicator != null)
			{
				long lookup = (long)((Agent)damagedAgent).m_replicator.OwningPlayer.Lookup;
				if (!_lastDamageByPlayer.TryGetValue(lookup, out DamageRecord value))
				{
					value = new DamageRecord();
					_lastDamageByPlayer[lookup] = value;
				}
				value.Damage = damage;
				value.DamagedAgent = damagedAgent;
				value.SourceAgent = sourceAgent;
				value.SourceType = sourceType;
				value.Timestamp = DateTime.Now;
			}
		}

		public static DamageRecord? GetLastDamage(long damagedAgent)
		{
			DamageRecord value;
			return _lastDamageByPlayer.TryGetValue(damagedAgent, out value) ? value : null;
		}

		public static void Reset()
		{
			_lastDamageByPlayer.Clear();
		}
	}
	public class DanosPatchConfiguration
	{
		public string TargetClass { get; set; }

		public string TargetMethod { get; set; }

		public string PostfixMethod { get; set; }
	}
	public static class DanosPatchManager
	{
		public static List<DanosPatchConfiguration> GetPatchConfigurations()
		{
			return new List<DanosPatchConfiguration>
			{
				new DanosPatchConfiguration
				{
					TargetClass = "GTFuckingXP.Scripts.XpHandler",
					TargetMethod = "AddXp",
					PostfixMethod = "GTFOStats.Patches.XpHandlerPatches.AddXpPostfix"
				}
			};
		}
	}
	public class DanosStaticStore
	{
		public const string ModVersion = "0.7.0";

		public static List<Func<string>> JsonContributors = new List<Func<string>>();

		public static DanosRunDownDataStore currentRunDownDataStore { get; set; } = new DanosRunDownDataStore();


		public static void RegisterJsonContributor(Func<string> contributor)
		{
			if (contributor != null)
			{
				JsonContributors.Add(contributor);
			}
		}
	}
	public class DanosRunDownDataStore
	{
		public bool wasHost { get; set; } = false;


		public string mv { get; set; } = "0.7.0";


		public string rer { get; set; } = "";


		public long st { get; set; } = 0L;


		public long et { get; set; } = 0L;


		public string rid { get; set; } = "";


		public string en { get; set; } = "";


		public string ei { get; set; } = "";


		public string rsg { get; set; } = "";


		public long msid { get; set; } = 0L;


		public uint xp { get; set; } = 0u;


		public int bioscanStarts { get; set; } = 0;


		public int scoutEnemiesDead { get; set; } = 0;


		public int enemiesDead { get; set; } = 0;


		public int enemyWavesSpawned { get; set; } = 0;


		public int scoutEnemiesFoundPlayer { get; set; } = 0;


		public int hibernatingEnemiesDead { get; set; } = 0;


		public int hibernatingEnemiesWokeUp { get; set; } = 0;


		public int enemiesDeadFromMelee { get; set; } = 0;


		public int scoutEnemiesDeadFromMelee { get; set; } = 0;


		public DanosExtraRundownData extraData { get; set; } = new DanosExtraRundownData();


		public Dictionary<long, string> pl { get; set; } = new Dictionary<long, string>();


		public Dictionary<long, List<DanosPositionalData>> pd { get; set; } = new Dictionary<long, List<DanosPositionalData>>();


		public Dictionary<long, DanosSummaryData> sd { get; set; } = new Dictionary<long, DanosSummaryData>();


		public Dictionary<long, DanosDeathSummary> ds { get; set; } = new Dictionary<long, DanosDeathSummary>();


		public Dictionary<string, int> edc { get; set; } = new Dictionary<string, int>();


		public void IncrementBioscanStart()
		{
			bioscanStarts++;
		}

		public void IncrementScoutEnemiesDead()
		{
			scoutEnemiesDead++;
		}

		public void IncrementEnemiesDead()
		{
			enemiesDead++;
		}

		public void IncrementEnemyWavesSpawned()
		{
			enemyWavesSpawned++;
		}

		public void IncrementScoutEnemiesFoundPlayer()
		{
			scoutEnemiesFoundPlayer++;
		}

		public void IncrementHibernatingEnemiesDead()
		{
			hibernatingEnemiesDead++;
		}

		public void IncrementHibernatingEnemiesWokeUp()
		{
			hibernatingEnemiesWokeUp++;
		}

		public void IncrementEnemiesDeadFromMelee()
		{
			enemiesDeadFromMelee++;
		}

		public void IncrementScoutEnemiesDeadFromMelee()
		{
			scoutEnemiesDeadFromMelee++;
		}

		public void AddEnemyDeathCount(string enemyName)
		{
			if (edc.ContainsKey(enemyName))
			{
				edc[enemyName]++;
			}
			else
			{
				edc[enemyName] = 1;
			}
			Debug.Log(Object.op_Implicit("Enemy Death Count: " + enemyName + " " + edc[enemyName]));
		}

		public void AddPlayerDownData(long sid, PlayerAgent playerAgent)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			if (!sd.ContainsKey(sid))
			{
				sd[sid] = new DanosSummaryData();
			}
			sd[sid].downs++;
			if (!ds.ContainsKey(sid))
			{
				ds[sid] = new DanosDeathSummary();
			}
			ds[sid].x = ((Component)playerAgent).transform.position.x;
			ds[sid].z = ((Component)playerAgent).transform.position.z;
			ds[sid].ts = DateTimeOffset.Now.ToUnixTimeSeconds();
			DanosDamageInfoStore.DamageRecord lastDamage = DanosDamageInfoStore.GetLastDamage(sid);
			DanosDamageInfoStore.DamageRecord value = DanosDamageInfoStore._lastDamageByPlayer[sid];
			string text = JsonSerializer.Serialize(value);
			Debug.Log(Object.op_Implicit(text));
			if (lastDamage == null)
			{
				ds[sid].cause = "Unknown";
			}
			else
			{
				ds[sid].cause = lastDamage.SourceType;
			}
		}

		public void AddPlayerReloadData(long sid)
		{
			if (!sd.ContainsKey(sid))
			{
				sd[sid] = new DanosSummaryData();
			}
			sd[sid].reloads++;
		}

		public void AddPlayerHealthPackUsed(long sid)
		{
			if (!sd.ContainsKey(sid))
			{
				sd[sid] = new DanosSummaryData();
			}
			sd[sid].healthpacksused++;
		}

		public void AddPlayerAmmoPackUsed(long sid)
		{
			if (!sd.ContainsKey(sid))
			{
				sd[sid] = new DanosSummaryData();
			}
			sd[sid].ammopacksused++;
		}

		public void AddPlayerArtifactPickup(long sid)
		{
			if (!sd.ContainsKey(sid))
			{
				sd[sid] = new DanosSummaryData();
			}
			sd[sid].artifacts++;
		}

		public void AddPlayerDisinfectionUsed(long sid)
		{
			if (!sd.ContainsKey(sid))
			{
				sd[sid] = new DanosSummaryData();
			}
			sd[sid].disinfections++;
		}

		public void AddPlayerTripMinePlaced(long sid)
		{
			if (!sd.ContainsKey(sid))
			{
				sd[sid] = new DanosSummaryData();
			}
			sd[sid].tripminesplaced++;
		}

		public void AddPlayerKeyCardPickup(long sid)
		{
			if (!sd.ContainsKey(sid))
			{
				sd[sid] = new DanosSummaryData();
			}
			sd[sid].keycards++;
		}

		public void AddPlayerHackingSuccess(long sid)
		{
			if (!sd.ContainsKey(sid))
			{
				sd[sid] = new DanosSummaryData();
			}
			sd[sid].hackingSuccesses++;
		}

		public void AddXP(uint xp)
		{
			this.xp += xp;
		}

		public void AddPositionalData(DanosPositionalDataTransfer dataTransfer)
		{
			if (!pl.ContainsKey(dataTransfer.sid))
			{
				pl[dataTransfer.sid] = dataTransfer.Name;
			}
			if (!pd.ContainsKey(dataTransfer.sid))
			{
				pd[dataTransfer.sid] = new List<DanosPositionalData>();
			}
			pd[dataTransfer.sid].Add(new DanosPositionalData
			{
				x = (float)dataTransfer.x,
				z = (float)dataTransfer.z,
				rt = (int)dataTransfer.Timestamp
			});
		}

		public void AddPlayerToSummary(long lookup, PlayerAgent playerAgent)
		{
			if (!pl.ContainsKey(lookup))
			{
				pl[lookup] = playerAgent.PlayerName;
			}
			if (!sd.ContainsKey(lookup))
			{
				sd[lookup] = new DanosSummaryData();
			}
		}
	}
	public class DanosPositionalData
	{
		[JsonConverter(typeof(OneDecimalJsonConverter))]
		public float x { get; set; }

		[JsonConverter(typeof(OneDecimalJsonConverter))]
		public float z { get; set; }

		public int rt { get; set; }
	}
	public class DanosPositionalDataTransfer
	{
		public double x { get; set; }

		public double z { get; set; }

		public long Timestamp { get; set; }

		public long sid { get; set; }

		public string Name { get; set; }
	}
	public class DanosDeathSummary
	{
		[JsonConverter(typeof(OneDecimalJsonConverter))]
		public float x { get; set; } = 0f;


		[JsonConverter(typeof(OneDecimalJsonConverter))]
		public float z { get; set; } = 0f;


		public long ts { get; set; } = 0L;


		public string cause { get; set; } = "";

	}
	public class DanosExtraRundownData
	{
		public string storyTitle { get; set; } = "";


		public string storyDescription { get; set; } = "";


		public string rundownKey { get; set; } = "";


		public string rundownprefix { get; set; } = "";


		public string rundownName { get; set; } = "";


		public string devInfo { get; set; } = "";


		public string matchmakingtier { get; set; } = "";


		public string desc2 { get; set; } = "";


		public string depth { get; set; } = "";


		public string otherTitle { get; set; } = "";

	}
	public class DanosSummaryData
	{
		public int reloads { get; set; } = 0;


		public int downs { get; set; } = 0;


		public int healthpacksused { get; set; } = 0;


		public int ammopacksused { get; set; } = 0;


		public int artifacts { get; set; } = 0;


		public int disinfections { get; set; } = 0;


		public int tripminesplaced { get; set; } = 0;


		public int keycards { get; set; } = 0;


		public int hackingSuccesses { get; set; } = 0;

	}
	public class OneDecimalJsonConverter : JsonConverter<float>
	{
		public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			return (float)reader.GetDouble();
		}

		public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options)
		{
			writer.WriteNumberValue(Math.Round(value, 1));
		}
	}
	public class PolicyVersion
	{
		public string Version { get; set; } = "1.0.1";


		public DateTime LastUpdated { get; set; } = new DateTime(2025, 1, 16);


		public string DescriptionOfChanges { get; set; } = "Newly drafted policy to clear some things up.";


		public string LastUpdatedDaysAgo => $"{(DateTime.UtcNow - LastUpdated).Days} day(s) ago";
	}
}