Decompiled source of GTFOStats v0.5.4

Danos-GTFOStats.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
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 GTFOStats.Data;
using GTFOStats.Patches;
using GameData;
using GameEvent;
using HarmonyLib;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Localization;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".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+a051f01da11965b6cb59b661659a7a43d6a851c8")]
[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.5.4")]
	public class Plugin : BasePlugin
	{
		public override void Load()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			((BasePlugin)this).Log.LogInfo((object)"GTFOStats is loaded!");
			Harmony val = new Harmony("danos.GTFOStats");
			val.PatchAll(typeof(GameStatePatch));
		}
	}
}
namespace GTFOStats.Patches
{
	[HarmonyPatch]
	internal 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();
				return;
			}
			if (text == "gs_ExpeditionFail" || text == "gs_ExpeditionSuccess")
			{
				Console.WriteLine("Expedition ended");
				ExportRunDownData(text);
				StopPositionCollector();
				return;
			}
			switch (text)
			{
			case "gs_ExpeditionAbort":
				Console.WriteLine("Expedition Aborted");
				ExportRunDownData(text);
				StopPositionCollector();
				break;
			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);
					}
				}
				string json = JsonSerializer.Serialize(DanosStaticStore.currentRunDownDataStore, 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_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				pActiveExpedition activeExpeditionData = RundownManager.GetActiveExpeditionData();
				if ((int)activeExpeditionData.tier != 1 || activeExpeditionData.expeditionIndex == 0)
				{
				}
				RundownName currentRundownName = AchievementManager.GetCurrentRundownName();
				string rid = ((object)(RundownName)(ref currentRundownName)).ToString();
				eRundownTier val = activeExpeditionData.tier;
				string en = ((object)(eRundownTier)(ref val)).ToString();
				string text = activeExpeditionData.expeditionIndex.ToString();
				string rsg = activeExpeditionData.sessionGUID.m_data.ToString();
				DanosExtraRundownData extraData = new DanosExtraRundownData();
				try
				{
					string storyTitle = "";
					string otherTitle = "";
					string storyDescription = "";
					uint num = default(uint);
					if (RundownManager.TryGetIdFromLocalRundownKey(RundownManager.ActiveRundownKey, ref num))
					{
						RundownDataBlock block = GameDataBlockBase<RundownDataBlock>.GetBlock(num);
						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 rundownprefix = descriptive.Prefix + ((!descriptive.SkipExpNumberInName) ? (text + 1).ToString() : "");
					string rundownName = descriptive.PublicName + (descriptive.IsExtraExpedition ? "://EXT" : "");
					string devInfo = descriptive.DevInfo;
					val = descriptive.CustomMatchmakingTier;
					string matchmakingtier = ((object)(eRundownTier)(ref val)).ToString();
					string desc = LocalizedText.op_Implicit(descriptive.ExpeditionDescription);
					string depth = descriptive.ExpeditionDepth.ToString();
					extraData = new DanosExtraRundownData
					{
						rundownKey = RundownManager.ActiveRundownKey,
						rundownName = rundownName,
						otherTitle = otherTitle,
						rundownprefix = rundownprefix,
						storyDescription = storyDescription,
						storyTitle = storyTitle,
						devInfo = devInfo,
						matchmakingtier = matchmakingtier,
						desc2 = desc,
						depth = depth
					};
				}
				catch (Exception ex)
				{
					Debug.LogError(Object.op_Implicit("Error initializing DanosExtraRundownData: " + ex.Message));
				}
				DanosRunDownDataStore currentRunDownDataStore = new DanosRunDownDataStore
				{
					st = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
					rid = rid,
					en = en,
					ei = text,
					rsg = rsg,
					msid = GetLocalPlayerSteamID(),
					mv = "0.5.4",
					extraData = extraData
				};
				DanosStaticStore.currentRunDownDataStore = currentRunDownDataStore;
			}
			catch (Exception ex2)
			{
				Debug.LogError(Object.op_Implicit("Error initializing DanosRunDownDataStore: " + ex2.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));
			}
		}

		private static long GetLocalPlayerSteamID()
		{
			try
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				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 0L;
			}
		}

		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; }
	}
}
namespace GTFOStats.Data
{
	public class DanosStaticStore
	{
		public const string ModVersion = "0.5.4";

		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.5.4";


		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 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 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 AddPlayerDownData(long sid, PlayerAgent playerAgent)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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;
		}

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