Decompiled source of LiveStats v1.0.5

LiveStats.dll

Decompiled 2 hours ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LiveStatsMod.Overlay;
using LiveStatsMod.Stats;
using Microsoft.CodeAnalysis;
using Steamworks.Data;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("LiveStats")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LiveStats")]
[assembly: AssemblyTitle("LiveStats")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 LiveStatsMod
{
	internal class HeartbeatDriver : MonoBehaviour
	{
		public ConfigEntry<float> IntervalSeconds;

		private float _timer;

		private void Awake()
		{
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
		}

		private void OnDestroy()
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)"HeartbeatDriver was destroyed - live stats will stop updating until relaunch.");
			}
		}

		private void Update()
		{
			_timer += Time.unscaledDeltaTime;
			if (_timer >= IntervalSeconds.Value)
			{
				_timer = 0f;
				StatsBroadcaster.Refresh();
			}
		}
	}
	[BepInPlugin("alterego.livestats", "LiveStats", "1.0.5")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "alterego.livestats";

		public const string Name = "LiveStats";

		public const string Version = "1.0.5";

		internal static ManualLogSource Log;

		internal static ConfigEntry<float> HeartbeatSeconds;

		internal static ConfigEntry<bool> OverlayEnabled;

		internal static ConfigEntry<bool> ShowStreamSchedule;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			HeartbeatSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Overlay", "HeartbeatSeconds", 1f, "How often (seconds) to refresh live stats even without a discrete game event, so timers/quota countdowns stay live.");
			OverlayEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Overlay", "Enabled", true, "Show the in-game HUD overlay (day, moon, weather, quota, average scrap per day, scrap on ship).");
			ShowStreamSchedule = ((BaseUnityPlugin)this).Config.Bind<bool>("PauseMenu", "ShowStreamSchedule", false, "Show a small \"STREAM SCHEDULE\" box in the pause menu's Stats tab. Off by default since the schedule text baked into the mod belongs to its original author - only turn this on if that's you.");
			_harmony = new Harmony("alterego.livestats");
			_harmony.PatchAll();
			PlayerLifetimeStats.ResetAllHighestQuotasOnce();
			PlayerLifetimeStats.ResetArchNemesisTallyOnce();
			Log.LogInfo((object)"LiveStats v1.0.5 loaded.");
		}

		internal static void SpawnHeartbeat()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			new GameObject("LiveStats_Heartbeat").AddComponent<HeartbeatDriver>().IntervalSeconds = HeartbeatSeconds;
		}

		internal static void SpawnOverlay()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			new GameObject("LiveStats_Overlay").AddComponent<OverlayDriver>();
		}
	}
}
namespace LiveStatsMod.Stats
{
	internal static class EnemyAttackTracker
	{
		private static readonly TimeSpan FreshWindow = TimeSpan.FromSeconds(15.0);

		private static readonly ConcurrentDictionary<int, (string EnemyName, DateTime RecordedAt)> LastAttacker = new ConcurrentDictionary<int, (string, DateTime)>();

		public static void Record(PlayerControllerB player, EnemyAI enemy)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)enemy == (Object)null) && !((Object)(object)enemy.enemyType == (Object)null))
			{
				LastAttacker[(int)player.playerClientId] = (enemy.enemyType.enemyName, DateTime.UtcNow);
			}
		}

		public static bool TryGetAttacker(int playerClientId, out string enemyName)
		{
			if (LastAttacker.TryGetValue(playerClientId, out (string, DateTime) value) && DateTime.UtcNow - value.Item2 <= FreshWindow)
			{
				(enemyName, _) = value;
				return true;
			}
			enemyName = null;
			return false;
		}

		public static void ClearAll()
		{
			LastAttacker.Clear();
		}
	}
	internal static class LiveStats
	{
		public static bool InSaveFile;

		public static int DayNumber = 1;

		public static int Seed;

		public static string MoonName = "";

		public static string Weather = "";

		public static float TimeUntilDeadline;

		public static int DaysUntilDeadline;

		public static int ProfitQuota;

		public static int QuotaFulfilled;

		public static int ScrapValueOnShip;

		public static int AverageScrapSum;

		public static int AverageScrapDayCount;

		public static int QuotaNumber;

		public static int LastObservedProfitQuota = -1;

		public static int ScrapValueCollected;

		public static int LastDayScrapCollected;

		public static bool IsLanded;

		public static DateTime? MoonArrivedAt;

		public static bool WasInSaveFile;

		public static string OnScreenMessage = "";

		public static double CurrentRunMoonSeconds;

		public static bool CurrentRunSegmentActive;

		public static DateTime? CurrentRunSegmentStartedAt;

		public static double CurrentRunDowntimeSeconds;

		public static bool DowntimeActive;

		public static DateTime? DowntimeSegmentStartedAt;

		public static string PersistedValuesLoadedForSave;

		public static readonly ConcurrentDictionary<ulong, PlayerStats> Players = new ConcurrentDictionary<ulong, PlayerStats>();

		private const string CrewDeathsKey = "LCLiveStatsTracker_CrewDeaths";

		private static readonly Dictionary<string, int> PersistedCrewDeathsByUsername = new Dictionary<string, int>();

		public static int AverageScrapPerDay()
		{
			if (AverageScrapDayCount != 0)
			{
				return (int)Math.Round((double)AverageScrapSum / (double)AverageScrapDayCount);
			}
			return 0;
		}

		public static void LoadPersistedAverage(string saveFileName)
		{
			AverageScrapSum = ES3.Load<int>("LCLiveStatsTracker_AvgScrapSum", saveFileName, 0);
			AverageScrapDayCount = ES3.Load<int>("LCLiveStatsTracker_AvgScrapDayCount", saveFileName, 0);
		}

		public static void LoadPersistedRunMoonSeconds(string saveFileName)
		{
			CurrentRunMoonSeconds = ES3.Load<double>("LCLiveStatsTracker_RunMoonSeconds", saveFileName, 0.0);
		}

		public static void LoadPersistedDowntime(string saveFileName)
		{
			CurrentRunDowntimeSeconds = ES3.Load<double>("LCLiveStatsTracker_RunDowntimeSeconds", saveFileName, 0.0);
		}

		public static void LoadPersistedCrewDeaths(string saveFileName)
		{
			PersistedCrewDeathsByUsername.Clear();
			foreach (KeyValuePair<string, int> item in ES3.Load<Dictionary<string, int>>("LCLiveStatsTracker_CrewDeaths", saveFileName, new Dictionary<string, int>()))
			{
				PersistedCrewDeathsByUsername[item.Key] = item.Value;
			}
		}

		public static int GetPersistedDeathCount(string username)
		{
			if (string.IsNullOrEmpty(username) || !PersistedCrewDeathsByUsername.TryGetValue(username, out var value))
			{
				return 0;
			}
			return value;
		}

		public static void ResetRunScopedStatsInMemory()
		{
			AverageScrapSum = 0;
			AverageScrapDayCount = 0;
			CurrentRunMoonSeconds = 0.0;
			CurrentRunDowntimeSeconds = 0.0;
			PersistedCrewDeathsByUsername.Clear();
		}

		public static void PersistCrewDeath(string username, int deathCount, string saveFileName)
		{
			PersistedCrewDeathsByUsername[username] = deathCount;
			if (!string.IsNullOrEmpty(saveFileName))
			{
				Dictionary<string, int> dictionary = ES3.Load<Dictionary<string, int>>("LCLiveStatsTracker_CrewDeaths", saveFileName, new Dictionary<string, int>());
				dictionary[username] = deathCount;
				ES3.Save<Dictionary<string, int>>("LCLiveStatsTracker_CrewDeaths", dictionary, saveFileName);
			}
		}

		public static void ResetCrewDeaths(string saveFileName)
		{
			foreach (PlayerStats value in Players.Values)
			{
				value.DeathCount = 0;
			}
			PersistedCrewDeathsByUsername.Clear();
			if (!string.IsNullOrEmpty(saveFileName))
			{
				ES3.Save<Dictionary<string, int>>("LCLiveStatsTracker_CrewDeaths", new Dictionary<string, int>(), saveFileName);
			}
		}

		public static void ResetForNewSession()
		{
			DayNumber = 1;
			Seed = 0;
			MoonName = "";
			Weather = "";
			TimeUntilDeadline = 0f;
			DaysUntilDeadline = 0;
			ProfitQuota = 0;
			QuotaFulfilled = 0;
			ScrapValueOnShip = 0;
			QuotaNumber = 0;
			LastObservedProfitQuota = -1;
			ScrapValueCollected = 0;
			LastDayScrapCollected = 0;
			IsLanded = false;
			MoonArrivedAt = null;
			CurrentRunSegmentActive = false;
			CurrentRunSegmentStartedAt = null;
			DowntimeActive = false;
			DowntimeSegmentStartedAt = null;
			PersistedValuesLoadedForSave = null;
			Players.Clear();
		}
	}
	internal class PlayerStats
	{
		public string Name;

		public bool Alive = true;

		public bool Disconnected;

		public string CauseOfDeath;

		public int DeathCount;

		public int JumpsThisRound;
	}
	internal static class LobbyPrivacy
	{
		public const string PublicDataKey = "LiveStats_Public";

		public static bool IsCurrentLobbyPublic()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			Lobby? val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.currentLobby : ((Lobby?)null));
			if (!val.HasValue)
			{
				return false;
			}
			Lobby value = val.Value;
			return ((Lobby)(ref value)).GetData("LiveStats_Public") == "1";
		}
	}
	internal static class PlayerLifetimeStats
	{
		private const string GlobalFile = "LCLiveStatsTracker_GlobalPlayerStats";

		private const string KnownPlayersKey = "LCLiveStatsTracker_KnownPlayers";

		private const string HighestQuotaResetDoneKey = "LCLiveStatsTracker_HighestQuotaResetDone";

		private const string ArchNemesisResetDoneKey = "LCLiveStatsTracker_ArchNemesisResetDone";

		private static readonly string[] AllSuffixes = new string[15]
		{
			"DaysSurvived", "CurrentStreak", "MaxStreak", "TotalSteps", "TotalScrapCollected", "ScrapDayCount", "TotalJumps", "TotalDamageTaken", "HighestQuota", "MoonVisits",
			"TotalMoonTimeSeconds", "TotalDeaths", "DeathCauses", "DeathMoons", "EnemyKills"
		};

		private static string Key(string username, string suffix)
		{
			return "LCLiveStatsTracker_P_" + username + "_" + suffix;
		}

		private static void RememberPlayer(string username)
		{
			List<string> list = ES3.Load<List<string>>("LCLiveStatsTracker_KnownPlayers", "LCLiveStatsTracker_GlobalPlayerStats", new List<string>());
			if (!list.Contains(username))
			{
				list.Add(username);
				ES3.Save<List<string>>("LCLiveStatsTracker_KnownPlayers", list, "LCLiveStatsTracker_GlobalPlayerStats");
			}
		}

		public static void RecordDayEnd(string username, bool survived, int stepsThisRound, int scrapThisRound, int jumpsThisRound, int damageTakenThisRound, int currentQuota, string moonName, bool countsForMoon)
		{
			if (string.IsNullOrEmpty(username))
			{
				return;
			}
			RememberPlayer(username);
			if (survived)
			{
				ES3.Save<int>(Key(username, "DaysSurvived"), ES3.Load<int>(Key(username, "DaysSurvived"), "LCLiveStatsTracker_GlobalPlayerStats", 0) + 1, "LCLiveStatsTracker_GlobalPlayerStats");
				int num = ES3.Load<int>(Key(username, "CurrentStreak"), "LCLiveStatsTracker_GlobalPlayerStats", 0) + 1;
				ES3.Save<int>(Key(username, "CurrentStreak"), num, "LCLiveStatsTracker_GlobalPlayerStats");
				if (num > ES3.Load<int>(Key(username, "MaxStreak"), "LCLiveStatsTracker_GlobalPlayerStats", 0))
				{
					ES3.Save<int>(Key(username, "MaxStreak"), num, "LCLiveStatsTracker_GlobalPlayerStats");
				}
			}
			else
			{
				ES3.Save<int>(Key(username, "CurrentStreak"), 0, "LCLiveStatsTracker_GlobalPlayerStats");
			}
			if (stepsThisRound > 0)
			{
				ES3.Save<int>(Key(username, "TotalSteps"), ES3.Load<int>(Key(username, "TotalSteps"), "LCLiveStatsTracker_GlobalPlayerStats", 0) + stepsThisRound, "LCLiveStatsTracker_GlobalPlayerStats");
			}
			if (scrapThisRound > 0)
			{
				ES3.Save<int>(Key(username, "TotalScrapCollected"), ES3.Load<int>(Key(username, "TotalScrapCollected"), "LCLiveStatsTracker_GlobalPlayerStats", 0) + scrapThisRound, "LCLiveStatsTracker_GlobalPlayerStats");
			}
			if (countsForMoon)
			{
				ES3.Save<int>(Key(username, "ScrapDayCount"), ES3.Load<int>(Key(username, "ScrapDayCount"), "LCLiveStatsTracker_GlobalPlayerStats", 0) + 1, "LCLiveStatsTracker_GlobalPlayerStats");
			}
			if (jumpsThisRound > 0)
			{
				ES3.Save<int>(Key(username, "TotalJumps"), ES3.Load<int>(Key(username, "TotalJumps"), "LCLiveStatsTracker_GlobalPlayerStats", 0) + jumpsThisRound, "LCLiveStatsTracker_GlobalPlayerStats");
			}
			if (damageTakenThisRound > 0)
			{
				ES3.Save<int>(Key(username, "TotalDamageTaken"), ES3.Load<int>(Key(username, "TotalDamageTaken"), "LCLiveStatsTracker_GlobalPlayerStats", 0) + damageTakenThisRound, "LCLiveStatsTracker_GlobalPlayerStats");
			}
			if (!LobbyPrivacy.IsCurrentLobbyPublic() && currentQuota > ES3.Load<int>(Key(username, "HighestQuota"), "LCLiveStatsTracker_GlobalPlayerStats", 0))
			{
				ES3.Save<int>(Key(username, "HighestQuota"), currentQuota, "LCLiveStatsTracker_GlobalPlayerStats");
			}
			if (countsForMoon && !string.IsNullOrEmpty(moonName))
			{
				Dictionary<string, int> dictionary = ES3.Load<Dictionary<string, int>>(Key(username, "MoonVisits"), "LCLiveStatsTracker_GlobalPlayerStats", new Dictionary<string, int>());
				dictionary[moonName] = ((!dictionary.TryGetValue(moonName, out var value)) ? 1 : (value + 1));
				ES3.Save<Dictionary<string, int>>(Key(username, "MoonVisits"), dictionary, "LCLiveStatsTracker_GlobalPlayerStats");
			}
		}

		public static void RecordMoonTime(string username, double elapsedSeconds)
		{
			if (!string.IsNullOrEmpty(username) && !(elapsedSeconds <= 0.0))
			{
				RememberPlayer(username);
				double num = ES3.Load<double>(Key(username, "TotalMoonTimeSeconds"), "LCLiveStatsTracker_GlobalPlayerStats", 0.0) + elapsedSeconds;
				ES3.Save<double>(Key(username, "TotalMoonTimeSeconds"), num, "LCLiveStatsTracker_GlobalPlayerStats");
			}
		}

		public static void RecordDeath(string username, string cause, string moonName, string killedBy)
		{
			if (!string.IsNullOrEmpty(username))
			{
				RememberPlayer(username);
				ES3.Save<int>(Key(username, "TotalDeaths"), ES3.Load<int>(Key(username, "TotalDeaths"), "LCLiveStatsTracker_GlobalPlayerStats", 0) + 1, "LCLiveStatsTracker_GlobalPlayerStats");
				Dictionary<string, int> dictionary = ES3.Load<Dictionary<string, int>>(Key(username, "DeathCauses"), "LCLiveStatsTracker_GlobalPlayerStats", new Dictionary<string, int>());
				dictionary[cause] = ((!dictionary.TryGetValue(cause, out var value)) ? 1 : (value + 1));
				ES3.Save<Dictionary<string, int>>(Key(username, "DeathCauses"), dictionary, "LCLiveStatsTracker_GlobalPlayerStats");
				if (!string.IsNullOrEmpty(moonName))
				{
					Dictionary<string, int> dictionary2 = ES3.Load<Dictionary<string, int>>(Key(username, "DeathMoons"), "LCLiveStatsTracker_GlobalPlayerStats", new Dictionary<string, int>());
					dictionary2[moonName] = ((!dictionary2.TryGetValue(moonName, out var value2)) ? 1 : (value2 + 1));
					ES3.Save<Dictionary<string, int>>(Key(username, "DeathMoons"), dictionary2, "LCLiveStatsTracker_GlobalPlayerStats");
				}
				if (!string.IsNullOrEmpty(killedBy))
				{
					Dictionary<string, int> dictionary3 = ES3.Load<Dictionary<string, int>>(Key(username, "EnemyKills"), "LCLiveStatsTracker_GlobalPlayerStats", new Dictionary<string, int>());
					dictionary3[killedBy] = ((!dictionary3.TryGetValue(killedBy, out var value3)) ? 1 : (value3 + 1));
					ES3.Save<Dictionary<string, int>>(Key(username, "EnemyKills"), dictionary3, "LCLiveStatsTracker_GlobalPlayerStats");
				}
			}
		}

		public static List<string> GetKnownPlayers()
		{
			return ES3.Load<List<string>>("LCLiveStatsTracker_KnownPlayers", "LCLiveStatsTracker_GlobalPlayerStats", new List<string>());
		}

		public static bool RemovePlayer(string username)
		{
			List<string> knownPlayers = GetKnownPlayers();
			if (knownPlayers.RemoveAll((string n) => string.Equals(n, username, StringComparison.OrdinalIgnoreCase)) == 0)
			{
				return false;
			}
			string[] allSuffixes = AllSuffixes;
			foreach (string suffix in allSuffixes)
			{
				ES3.DeleteKey(Key(username, suffix), "LCLiveStatsTracker_GlobalPlayerStats");
			}
			ES3.Save<List<string>>("LCLiveStatsTracker_KnownPlayers", knownPlayers, "LCLiveStatsTracker_GlobalPlayerStats");
			return true;
		}

		public static void ResetAllHighestQuotasOnce()
		{
			if (ES3.Load<bool>("LCLiveStatsTracker_HighestQuotaResetDone", "LCLiveStatsTracker_GlobalPlayerStats", false))
			{
				return;
			}
			foreach (string knownPlayer in GetKnownPlayers())
			{
				ES3.Save<int>(Key(knownPlayer, "HighestQuota"), 0, "LCLiveStatsTracker_GlobalPlayerStats");
			}
			ES3.Save<bool>("LCLiveStatsTracker_HighestQuotaResetDone", true, "LCLiveStatsTracker_GlobalPlayerStats");
		}

		public static void ResetArchNemesisTallyOnce()
		{
			if (ES3.Load<bool>("LCLiveStatsTracker_ArchNemesisResetDone", "LCLiveStatsTracker_GlobalPlayerStats", false))
			{
				return;
			}
			foreach (string knownPlayer in GetKnownPlayers())
			{
				ES3.DeleteKey(Key(knownPlayer, "EnemyKills"), "LCLiveStatsTracker_GlobalPlayerStats");
			}
			ES3.Save<bool>("LCLiveStatsTracker_ArchNemesisResetDone", true, "LCLiveStatsTracker_GlobalPlayerStats");
		}

		public static string BuildProfileText(string username)
		{
			int num = ES3.Load<int>(Key(username, "DaysSurvived"), "LCLiveStatsTracker_GlobalPlayerStats", 0);
			int num2 = ES3.Load<int>(Key(username, "MaxStreak"), "LCLiveStatsTracker_GlobalPlayerStats", 0);
			int num3 = ES3.Load<int>(Key(username, "HighestQuota"), "LCLiveStatsTracker_GlobalPlayerStats", 0);
			int num4 = ES3.Load<int>(Key(username, "TotalDeaths"), "LCLiveStatsTracker_GlobalPlayerStats", 0);
			int num5 = ES3.Load<int>(Key(username, "TotalScrapCollected"), "LCLiveStatsTracker_GlobalPlayerStats", 0);
			int num6 = ES3.Load<int>(Key(username, "ScrapDayCount"), "LCLiveStatsTracker_GlobalPlayerStats", 0);
			int num7 = ES3.Load<int>(Key(username, "TotalSteps"), "LCLiveStatsTracker_GlobalPlayerStats", 0);
			int num8 = ES3.Load<int>(Key(username, "TotalJumps"), "LCLiveStatsTracker_GlobalPlayerStats", 0);
			int num9 = ES3.Load<int>(Key(username, "TotalDamageTaken"), "LCLiveStatsTracker_GlobalPlayerStats", 0);
			double totalSeconds = ES3.Load<double>(Key(username, "TotalMoonTimeSeconds"), "LCLiveStatsTracker_GlobalPlayerStats", 0.0);
			Dictionary<string, int> dictionary = ES3.Load<Dictionary<string, int>>(Key(username, "MoonVisits"), "LCLiveStatsTracker_GlobalPlayerStats", new Dictionary<string, int>());
			Dictionary<string, int> dictionary2 = ES3.Load<Dictionary<string, int>>(Key(username, "DeathMoons"), "LCLiveStatsTracker_GlobalPlayerStats", new Dictionary<string, int>());
			Dictionary<string, int> dictionary3 = ES3.Load<Dictionary<string, int>>(Key(username, "EnemyKills"), "LCLiveStatsTracker_GlobalPlayerStats", new Dictionary<string, int>());
			int num10 = ((num6 > 0) ? (num5 / num6) : 0);
			string text = ((dictionary.Count > 0) ? dictionary.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).First().Key : "-");
			string text2 = ((dictionary2.Count > 0) ? dictionary2.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).First().Key : "-");
			string text3 = ((dictionary3.Count > 0) ? dictionary3.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).First().Key : "-");
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("PROFILE: " + username);
			stringBuilder.AppendLine();
			stringBuilder.AppendLine($"Days Survived: {num}");
			stringBuilder.AppendLine($"Best Streak: {num2}");
			stringBuilder.AppendLine($"Highest Quota: ${num3}");
			stringBuilder.AppendLine($"Total Deaths: {num4}");
			stringBuilder.AppendLine($"Total Scrap Collected: ${num5}");
			stringBuilder.AppendLine($"Average Scrap/Day: ${num10}");
			stringBuilder.AppendLine("Favorite Moon: " + text);
			stringBuilder.AppendLine("Most Dangerous Moon: " + text2);
			stringBuilder.AppendLine("Total Time Spent On A Moon: " + FormatDuration(totalSeconds));
			stringBuilder.AppendLine($"Total Steps Taken: {num7}");
			stringBuilder.AppendLine($"Total Jumps: {num8}");
			stringBuilder.AppendLine($"Total Damage Taken: {num9}");
			stringBuilder.AppendLine("Arch Nemesis: " + text3);
			return stringBuilder.ToString();
		}

		private static string FormatDuration(double totalSeconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(totalSeconds);
			if (!(timeSpan.TotalHours >= 1.0))
			{
				return $"{timeSpan.Minutes}m {timeSpan.Seconds}s";
			}
			return $"{(int)timeSpan.TotalHours}h {timeSpan.Minutes}m";
		}
	}
	internal static class StatsBroadcaster
	{
		private const string ClientSessionMarker = "__client_session__";

		public static string GetPersistenceSaveFileName()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsHost)
			{
				return null;
			}
			if (!((Object)(object)GameNetworkManager.Instance != (Object)null))
			{
				return null;
			}
			return GameNetworkManager.Instance.currentSaveFileName;
		}

		public static void Refresh()
		{
			try
			{
				UpdateLiveStats();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"Failed to update live stats: {arg}");
			}
		}

		private static void UpdateLiveStats()
		{
			StartOfRound instance = StartOfRound.Instance;
			TimeOfDay instance2 = TimeOfDay.Instance;
			bool flag = (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsListening;
			if (flag && !LiveStats.WasInSaveFile)
			{
				LiveStats.ResetForNewSession();
			}
			LiveStats.WasInSaveFile = flag;
			LiveStats.InSaveFile = flag;
			if (flag)
			{
				if (NetworkManager.Singleton.IsHost)
				{
					string text = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.currentSaveFileName : null);
					if (!string.IsNullOrEmpty(text) && LiveStats.PersistedValuesLoadedForSave != text)
					{
						LiveStats.LoadPersistedAverage(text);
						LiveStats.LoadPersistedRunMoonSeconds(text);
						LiveStats.LoadPersistedDowntime(text);
						LiveStats.LoadPersistedCrewDeaths(text);
						LiveStats.PersistedValuesLoadedForSave = text;
					}
				}
				else if (LiveStats.PersistedValuesLoadedForSave != "__client_session__")
				{
					LiveStats.ResetRunScopedStatsInMemory();
					LiveStats.PersistedValuesLoadedForSave = "__client_session__";
				}
			}
			if (flag && (Object)(object)instance != (Object)null)
			{
				LiveStats.Seed = instance.randomMapSeed;
				LiveStats.MoonName = (((Object)(object)instance.currentLevel != (Object)null) ? instance.currentLevel.PlanetName : "");
				LiveStats.DayNumber = ((instance.gameStats != null) ? instance.gameStats.daysSpent : 0) + 1;
				if (instance.allPlayerScripts != null)
				{
					PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
					foreach (PlayerControllerB p in allPlayerScripts)
					{
						if (!((Object)(object)p == (Object)null) && (LiveStats.Players.ContainsKey(p.playerClientId) || p.isPlayerControlled || p.isPlayerDead || p.disconnectedMidGame))
						{
							PlayerStats orAdd = LiveStats.Players.GetOrAdd(p.playerClientId, (ulong _) => new PlayerStats
							{
								Name = p.playerUsername,
								DeathCount = LiveStats.GetPersistedDeathCount(p.playerUsername)
							});
							orAdd.Name = p.playerUsername;
							orAdd.Alive = !p.isPlayerDead;
							bool flag2 = instance.ClientPlayerList != null && instance.ClientPlayerList.ContainsKey(p.actualClientId);
							orAdd.Disconnected = p.disconnectedMidGame || !flag2;
						}
					}
				}
			}
			if (flag && (Object)(object)instance2 != (Object)null)
			{
				LiveStats.Weather = ((object)Unsafe.As<LevelWeatherType, LevelWeatherType>(ref instance2.currentLevelWeather)/*cast due to .constrained prefix*/).ToString();
				LiveStats.ProfitQuota = instance2.profitQuota;
				LiveStats.QuotaFulfilled = instance2.quotaFulfilled;
				LiveStats.TimeUntilDeadline = instance2.timeUntilDeadline;
				LiveStats.DaysUntilDeadline = instance2.daysUntilDeadline;
				if (LiveStats.LastObservedProfitQuota == -1)
				{
					LiveStats.QuotaNumber = instance2.timesFulfilledQuota + 1;
				}
				else if (instance2.profitQuota != LiveStats.LastObservedProfitQuota)
				{
					LiveStats.QuotaNumber++;
				}
				LiveStats.LastObservedProfitQuota = instance2.profitQuota;
				bool currentDayTimeStarted = instance2.currentDayTimeStarted;
				if (currentDayTimeStarted && !LiveStats.IsLanded)
				{
					LiveStats.MoonArrivedAt = DateTime.UtcNow;
				}
				else if (!currentDayTimeStarted && LiveStats.IsLanded && LiveStats.MoonArrivedAt.HasValue)
				{
					double totalSeconds = (DateTime.UtcNow - LiveStats.MoonArrivedAt.Value).TotalSeconds;
					if ((Object)(object)instance != (Object)null && instance.allPlayerScripts != null)
					{
						PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
						foreach (PlayerControllerB val in allPlayerScripts)
						{
							if (!((Object)(object)val == (Object)null) && !val.disconnectedMidGame && (val.isPlayerControlled || val.isPlayerDead))
							{
								PlayerLifetimeStats.RecordMoonTime(val.playerUsername, totalSeconds);
							}
						}
					}
				}
				LiveStats.IsLanded = currentDayTimeStarted;
				bool flag3 = !currentDayTimeStarted && (Object)(object)instance != (Object)null && (Object)(object)instance.currentLevel != (Object)null && !instance.currentLevel.spawnEnemiesAndScrap && instance.shipDoorsEnabled;
				bool flag4 = currentDayTimeStarted || flag3;
				if (flag4 && !LiveStats.CurrentRunSegmentActive)
				{
					LiveStats.CurrentRunSegmentStartedAt = DateTime.UtcNow;
				}
				else if (!flag4 && LiveStats.CurrentRunSegmentActive && LiveStats.CurrentRunSegmentStartedAt.HasValue)
				{
					double totalSeconds2 = (DateTime.UtcNow - LiveStats.CurrentRunSegmentStartedAt.Value).TotalSeconds;
					LiveStats.CurrentRunMoonSeconds += totalSeconds2;
					string persistenceSaveFileName = GetPersistenceSaveFileName();
					if (!string.IsNullOrEmpty(persistenceSaveFileName))
					{
						ES3.Save<double>("LCLiveStatsTracker_RunMoonSeconds", LiveStats.CurrentRunMoonSeconds, persistenceSaveFileName);
					}
				}
				LiveStats.CurrentRunSegmentActive = flag4;
				bool flag5 = !currentDayTimeStarted && !flag3;
				if (flag5 && !LiveStats.DowntimeActive)
				{
					LiveStats.DowntimeSegmentStartedAt = DateTime.UtcNow;
				}
				else if (!flag5 && LiveStats.DowntimeActive && LiveStats.DowntimeSegmentStartedAt.HasValue)
				{
					double totalSeconds3 = (DateTime.UtcNow - LiveStats.DowntimeSegmentStartedAt.Value).TotalSeconds;
					LiveStats.CurrentRunDowntimeSeconds += totalSeconds3;
					string persistenceSaveFileName2 = GetPersistenceSaveFileName();
					if (!string.IsNullOrEmpty(persistenceSaveFileName2))
					{
						ES3.Save<double>("LCLiveStatsTracker_RunDowntimeSeconds", LiveStats.CurrentRunDowntimeSeconds, persistenceSaveFileName2);
					}
				}
				LiveStats.DowntimeActive = flag5;
			}
			else
			{
				LiveStats.IsLanded = false;
			}
			if (flag && (Object)(object)instance != (Object)null)
			{
				LiveStats.ScrapValueOnShip = instance.GetValueOfAllScrap(true, false);
				LiveStats.ScrapValueCollected = ((instance.gameStats != null) ? instance.gameStats.scrapValueCollected : 0);
			}
		}
	}
	internal static class StatsSummaryText
	{
		private static readonly Regex PhantomPlayerName = new Regex("^Player #\\d+$", RegexOptions.IgnoreCase);

		public static string Build(bool richText)
		{
			string text = (richText ? "<b>" : "");
			string text2 = (richText ? "</b>" : "");
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(text + "CURRENT RUN: " + FormatElapsed() + text2);
			stringBuilder.AppendLine("Downtime: " + FormatDowntime());
			stringBuilder.AppendLine();
			stringBuilder.AppendLine($"Day: {LiveStats.DayNumber}");
			stringBuilder.AppendLine("Moon: " + ((!LiveStats.IsLanded) ? "In Orbit" : (string.IsNullOrEmpty(LiveStats.MoonName) ? "-" : LiveStats.MoonName)));
			stringBuilder.AppendLine("Weather: " + (LiveStats.IsLanded ? LiveStats.Weather : "-"));
			stringBuilder.AppendLine($"Quota {LiveStats.QuotaNumber}: ${LiveStats.ProfitQuota}");
			stringBuilder.AppendLine($"Scrap On Ship: ${LiveStats.ScrapValueOnShip}");
			stringBuilder.AppendLine($"Total Scrap Sold: ${LiveStats.ScrapValueCollected}");
			stringBuilder.AppendLine($"Average Scrap/Day: ${LiveStats.AverageScrapPerDay()}");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine(text + "CREW" + text2);
			bool flag = false;
			foreach (KeyValuePair<ulong, PlayerStats> player in LiveStats.Players)
			{
				if (!PhantomPlayerName.IsMatch((player.Value.Name ?? "").Trim()))
				{
					flag = true;
					PlayerStats value = player.Value;
					stringBuilder.AppendLine($"{value.Name}: {value.DeathCount} deaths");
				}
			}
			if (!flag)
			{
				stringBuilder.AppendLine("-");
			}
			return stringBuilder.ToString();
		}

		private static string FormatElapsed()
		{
			double num = LiveStats.CurrentRunMoonSeconds;
			if (LiveStats.CurrentRunSegmentActive && LiveStats.CurrentRunSegmentStartedAt.HasValue)
			{
				num += (DateTime.UtcNow - LiveStats.CurrentRunSegmentStartedAt.Value).TotalSeconds;
			}
			return FormatDuration(num);
		}

		private static string FormatDowntime()
		{
			double num = LiveStats.CurrentRunDowntimeSeconds;
			if (LiveStats.DowntimeActive && LiveStats.DowntimeSegmentStartedAt.HasValue)
			{
				num += (DateTime.UtcNow - LiveStats.DowntimeSegmentStartedAt.Value).TotalSeconds;
			}
			return FormatDuration(num);
		}

		private static string FormatDuration(double totalSeconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(totalSeconds);
			if (!(timeSpan.TotalHours >= 1.0))
			{
				return $"{timeSpan.Minutes:00}:{timeSpan.Seconds:00}";
			}
			return $"{(int)timeSpan.TotalHours}:{timeSpan.Minutes:00}:{timeSpan.Seconds:00}";
		}
	}
}
namespace LiveStatsMod.Patches
{
	internal static class EnemyAttackHelpers
	{
		public static void FromCollision(EnemyAI instance, Collider other)
		{
			EnemyAttackTracker.Record(instance.MeetsStandardPlayerCollisionConditions(other, false, false), instance);
		}

		public static void FromPlayerId(EnemyAI instance, int playerId)
		{
			StartOfRound instance2 = StartOfRound.Instance;
			if (!((Object)(object)instance2 == (Object)null) && instance2.allPlayerScripts != null && playerId >= 0 && playerId < instance2.allPlayerScripts.Length)
			{
				EnemyAttackTracker.Record(instance2.allPlayerScripts[playerId], instance);
			}
		}

		public static void FromLocalPlayer(EnemyAI instance)
		{
			EnemyAttackTracker.Record(((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null, instance);
		}
	}
	[HarmonyPatch(typeof(BaboonBirdAI), "OnCollideWithPlayer")]
	internal static class BaboonBirdAttackPatch
	{
		private static void Prefix(BaboonBirdAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(BlobAI), "OnCollideWithPlayer")]
	internal static class BlobAttackPatch
	{
		private static void Prefix(BlobAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(BushWolfEnemy), "OnCollideWithPlayer")]
	internal static class BushWolfAttackPatch
	{
		private static void Prefix(BushWolfEnemy __instance)
		{
			EnemyAttackTracker.Record(((EnemyAI)__instance).targetPlayer, (EnemyAI)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(ButlerBeesEnemyAI), "OnCollideWithPlayer")]
	internal static class ButlerBeesAttackPatch
	{
		private static void Prefix(ButlerBeesEnemyAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(ButlerEnemyAI), "OnCollideWithPlayer")]
	internal static class ButlerAttackPatch
	{
		private static void Prefix(ButlerEnemyAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(CadaverBloomAI))]
	internal static class CadaverBloomAttackPatch
	{
		[HarmonyPatch("BurstForth")]
		[HarmonyPrefix]
		private static void BurstForthPrefix(CadaverBloomAI __instance, PlayerControllerB player)
		{
			EnemyAttackTracker.Record(player, (EnemyAI)(object)__instance);
		}

		[HarmonyPatch("OnCollideWithPlayer")]
		[HarmonyPrefix]
		private static void CollidePrefix(CadaverBloomAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(CaveDwellerAI), "KillPlayerAnimationClientRpc")]
	internal static class CaveDwellerAttackPatch
	{
		private static void Prefix(CaveDwellerAI __instance, int playerObjectId)
		{
			EnemyAttackHelpers.FromPlayerId((EnemyAI)(object)__instance, playerObjectId);
		}
	}
	[HarmonyPatch(typeof(CentipedeAI), "DamagePlayerOnIntervals")]
	internal static class CentipedeAttackPatch
	{
		private static void Prefix(CentipedeAI __instance)
		{
			EnemyAttackTracker.Record(__instance.clingingToPlayer, (EnemyAI)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(ClaySurgeonAI), "OnCollideWithPlayer")]
	internal static class ClaySurgeonAttackPatch
	{
		private static void Prefix(ClaySurgeonAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(CrawlerAI), "OnCollideWithPlayer")]
	internal static class CrawlerAttackPatch
	{
		private static void Prefix(CrawlerAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(DressGirlAI), "OnCollideWithPlayer")]
	internal static class DressGirlAttackPatch
	{
		private static void Prefix(DressGirlAI __instance)
		{
			EnemyAttackTracker.Record(__instance.hauntingPlayer, (EnemyAI)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(FlowermanAI), "KillPlayerAnimationClientRpc")]
	internal static class FlowermanAttackPatch
	{
		private static void Prefix(FlowermanAI __instance, int playerObjectId)
		{
			EnemyAttackHelpers.FromPlayerId((EnemyAI)(object)__instance, playerObjectId);
		}
	}
	[HarmonyPatch(typeof(ForestGiantAI))]
	internal static class ForestGiantAttackPatch
	{
		[HarmonyPatch("AnimationEventA")]
		[HarmonyPrefix]
		private static void AnimationEventAPrefix(ForestGiantAI __instance)
		{
			EnemyAttackHelpers.FromLocalPlayer((EnemyAI)(object)__instance);
		}

		[HarmonyPatch("BeginEatPlayer")]
		[HarmonyPrefix]
		private static void BeginEatPlayerPrefix(ForestGiantAI __instance, PlayerControllerB playerBeingEaten)
		{
			EnemyAttackTracker.Record(playerBeingEaten, (EnemyAI)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(GiantKiwiAI), "AnimationEventB")]
	internal static class GiantKiwiAttackPatch
	{
		private static void Prefix(GiantKiwiAI __instance)
		{
			EnemyAttackHelpers.FromLocalPlayer((EnemyAI)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(HoarderBugAI), "OnCollideWithPlayer")]
	internal static class HoarderBugAttackPatch
	{
		private static void Prefix(HoarderBugAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(JesterAI), "KillPlayerClientRpc")]
	internal static class JesterAttackPatch
	{
		private static void Prefix(JesterAI __instance, int playerId)
		{
			EnemyAttackHelpers.FromPlayerId((EnemyAI)(object)__instance, playerId);
		}
	}
	[HarmonyPatch(typeof(LassoManAI), "OnCollideWithPlayer")]
	internal static class LassoManAttackPatch
	{
		private static void Prefix(LassoManAI __instance, Collider other)
		{
			EnemyAttackTracker.Record(((Component)other).gameObject.GetComponent<PlayerControllerB>(), (EnemyAI)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(MaskedPlayerEnemy), "KillPlayerAnimationClientRpc")]
	internal static class MaskedAttackPatch
	{
		private static void Prefix(MaskedPlayerEnemy __instance, int playerObjectId)
		{
			EnemyAttackHelpers.FromPlayerId((EnemyAI)(object)__instance, playerObjectId);
		}
	}
	[HarmonyPatch(typeof(MouthDogAI), "KillPlayerClientRpc")]
	internal static class MouthDogAttackPatch
	{
		private static void Prefix(MouthDogAI __instance, int playerId)
		{
			EnemyAttackHelpers.FromPlayerId((EnemyAI)(object)__instance, playerId);
		}
	}
	[HarmonyPatch(typeof(NutcrackerEnemyAI), "LegKickPlayer")]
	internal static class NutcrackerAttackPatch
	{
		private static void Prefix(NutcrackerEnemyAI __instance, int playerId)
		{
			EnemyAttackHelpers.FromPlayerId((EnemyAI)(object)__instance, playerId);
		}
	}
	[HarmonyPatch(typeof(PufferAI), "OnCollideWithPlayer")]
	internal static class PufferAttackPatch
	{
		private static void Prefix(PufferAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(PumaAI), "OnCollideWithPlayer")]
	internal static class PumaAttackPatch
	{
		private static void Prefix(PumaAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(RadMechAI))]
	internal static class RadMechAttackPatch
	{
		[HarmonyPatch("BeginTorchPlayer")]
		[HarmonyPrefix]
		private static void BeginTorchPlayerPrefix(RadMechAI __instance, PlayerControllerB playerBeingTorched)
		{
			EnemyAttackTracker.Record(playerBeingTorched, (EnemyAI)(object)__instance);
		}

		[HarmonyPatch("Stomp")]
		[HarmonyPrefix]
		private static void StompPrefix(RadMechAI __instance)
		{
			EnemyAttackHelpers.FromLocalPlayer((EnemyAI)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(RedLocustBees))]
	internal static class RedLocustBeesAttackPatch
	{
		[HarmonyPatch("BeeKillPlayerOnLocalClient")]
		[HarmonyPrefix]
		private static void BeeKillPrefix(RedLocustBees __instance, int playerId)
		{
			EnemyAttackHelpers.FromPlayerId((EnemyAI)(object)__instance, playerId);
		}

		[HarmonyPatch("OnCollideWithPlayer")]
		[HarmonyPrefix]
		private static void CollidePrefix(RedLocustBees __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(SandSpiderAI), "OnCollideWithPlayer")]
	internal static class SandSpiderAttackPatch
	{
		private static void Prefix(SandSpiderAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(SandWormAI), "EatPlayer")]
	internal static class SandWormAttackPatch
	{
		private static void Prefix(SandWormAI __instance, PlayerControllerB playerScript)
		{
			EnemyAttackTracker.Record(playerScript, (EnemyAI)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(SpringManAI), "OnCollideWithPlayer")]
	internal static class SpringManAttackPatch
	{
		private static void Prefix(SpringManAI __instance, Collider other)
		{
			EnemyAttackHelpers.FromCollision((EnemyAI)(object)__instance, other);
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "SteamMatchmaking_OnLobbyCreated")]
	internal static class LobbyPrivacyPatch
	{
		private static void Postfix(GameNetworkManager __instance, Lobby lobby)
		{
			bool flag = __instance.lobbyHostSettings != null && __instance.lobbyHostSettings.isLobbyPublic;
			((Lobby)(ref lobby)).SetData("LiveStats_Public", flag ? "1" : "0");
		}
	}
	[HarmonyPatch(typeof(MenuManager), "Start")]
	internal static class MenuManagerStartPatch
	{
		private static bool _spawned;

		private static void Postfix(MenuManager __instance)
		{
			if (!_spawned && !__instance.isInitScene)
			{
				_spawned = true;
				Plugin.SpawnHeartbeat();
				Plugin.SpawnOverlay();
			}
		}
	}
	[HarmonyPatch(typeof(QuickMenuManager), "Start")]
	internal static class QuickMenuStatsTabPatch
	{
		private static void Postfix(QuickMenuManager __instance)
		{
			try
			{
				PauseMenuStatsPanel.Install(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"Failed to install pause menu Stats tab: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(QuickMenuManager), "CloseQuickMenuPanels")]
	internal static class QuickMenuCloseStatsTabPatch
	{
		private static void Postfix()
		{
			try
			{
				PauseMenuStatsPanel.Close();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"Failed to close pause menu Stats tab: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(TimeOfDay), "OnDayChanged")]
	internal static class DayChangedPatch
	{
		private static void Postfix()
		{
			StatsBroadcaster.Refresh();
			EnemyAttackTracker.ClearAll();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "FirePlayersAfterDeadlineClientRpc")]
	internal static class PlayersFiredPatch
	{
		private static void Postfix()
		{
			StatsBroadcaster.Refresh();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ResetShip")]
	internal static class ShipResetPatch
	{
		private static void Postfix()
		{
			LiveStats.QuotaNumber = 0;
			LiveStats.LastObservedProfitQuota = -1;
			LiveStats.CurrentRunMoonSeconds = 0.0;
			LiveStats.CurrentRunSegmentActive = false;
			LiveStats.CurrentRunSegmentStartedAt = null;
			LiveStats.CurrentRunDowntimeSeconds = 0.0;
			LiveStats.DowntimeActive = false;
			LiveStats.DowntimeSegmentStartedAt = null;
			string persistenceSaveFileName = StatsBroadcaster.GetPersistenceSaveFileName();
			if (!string.IsNullOrEmpty(persistenceSaveFileName))
			{
				ES3.Save<double>("LCLiveStatsTracker_RunMoonSeconds", 0.0, persistenceSaveFileName);
				ES3.Save<double>("LCLiveStatsTracker_RunDowntimeSeconds", 0.0, persistenceSaveFileName);
			}
			LiveStats.ResetCrewDeaths(persistenceSaveFileName);
			foreach (PlayerStats value in LiveStats.Players.Values)
			{
				value.JumpsThisRound = 0;
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Awake")]
	internal static class JumpTrackingPatch
	{
		private static void Postfix(StartOfRound __instance)
		{
			((UnityEvent<PlayerControllerB>)(object)__instance.PlayerJumpEvent).AddListener((UnityAction<PlayerControllerB>)OnPlayerJump);
		}

		private static void OnPlayerJump(PlayerControllerB player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				LiveStats.Players.GetOrAdd(player.playerClientId, (ulong _) => new PlayerStats
				{
					Name = player.playerUsername,
					DeathCount = LiveStats.GetPersistedDeathCount(player.playerUsername)
				}).JumpsThisRound++;
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "EndOfGame")]
	internal static class EndOfDayScrapPatch
	{
		private static void Prefix(int scrapCollected)
		{
			LiveStats.LastDayScrapCollected = scrapCollected;
			StartOfRound instance = StartOfRound.Instance;
			string persistenceSaveFileName = StatsBroadcaster.GetPersistenceSaveFileName();
			SelectableLevel val = (((Object)(object)instance != (Object)null) ? instance.currentLevel : null);
			bool flag = (Object)(object)val != (Object)null && val.spawnEnemiesAndScrap;
			if (flag)
			{
				LiveStats.AverageScrapSum += scrapCollected;
				LiveStats.AverageScrapDayCount++;
				if (!string.IsNullOrEmpty(persistenceSaveFileName))
				{
					ES3.Save<int>("LCLiveStatsTracker_AvgScrapSum", LiveStats.AverageScrapSum, persistenceSaveFileName);
					ES3.Save<int>("LCLiveStatsTracker_AvgScrapDayCount", LiveStats.AverageScrapDayCount, persistenceSaveFileName);
				}
			}
			if (!((Object)(object)instance != (Object)null) || instance.gameStats == null || instance.allPlayerScripts == null)
			{
				return;
			}
			string moonName = (((Object)(object)val != (Object)null) ? val.PlanetName : null);
			int currentQuota = (((Object)(object)TimeOfDay.Instance != (Object)null) ? TimeOfDay.Instance.profitQuota : 0);
			PlayerStats[] allPlayerStats = instance.gameStats.allPlayerStats;
			for (int i = 0; i < instance.allPlayerScripts.Length && i < allPlayerStats.Length; i++)
			{
				PlayerControllerB val2 = instance.allPlayerScripts[i];
				if (!((Object)(object)val2 == (Object)null) && (val2.isPlayerControlled || val2.isPlayerDead || val2.disconnectedMidGame))
				{
					LiveStats.Players.TryGetValue(val2.playerClientId, out var value);
					int jumpsThisRound = value?.JumpsThisRound ?? 0;
					if (value != null)
					{
						value.JumpsThisRound = 0;
					}
					PlayerLifetimeStats.RecordDayEnd(val2.playerUsername, !val2.isPlayerDead, allPlayerStats[i].stepsTaken, allPlayerStats[i].profitable, jumpsThisRound, allPlayerStats[i].damageTaken, currentQuota, moonName, flag);
				}
			}
		}
	}
	[HarmonyPatch(typeof(HUDManager))]
	internal static class ControlTipSuppressPatch
	{
		private static bool ShouldSuppress()
		{
			if (Plugin.OverlayEnabled.Value)
			{
				return LiveStats.InSaveFile;
			}
			return false;
		}

		[HarmonyPatch("ChangeControlTip")]
		[HarmonyPrefix]
		private static bool ChangeControlTipPrefix()
		{
			return !ShouldSuppress();
		}

		[HarmonyPatch("ChangeControlTipMultiple")]
		[HarmonyPrefix]
		private static bool ChangeControlTipMultiplePrefix()
		{
			return !ShouldSuppress();
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "ResetSavedGameValues")]
	internal static class ResetSavedGameValuesPatch
	{
		private static void Postfix(GameNetworkManager __instance)
		{
			LiveStats.AverageScrapSum = 0;
			LiveStats.AverageScrapDayCount = 0;
			LiveStats.CurrentRunMoonSeconds = 0.0;
			LiveStats.CurrentRunDowntimeSeconds = 0.0;
			ES3.Save<int>("LCLiveStatsTracker_AvgScrapSum", 0, __instance.currentSaveFileName);
			ES3.Save<int>("LCLiveStatsTracker_AvgScrapDayCount", 0, __instance.currentSaveFileName);
			ES3.Save<double>("LCLiveStatsTracker_RunMoonSeconds", 0.0, __instance.currentSaveFileName);
			ES3.Save<double>("LCLiveStatsTracker_RunDowntimeSeconds", 0.0, __instance.currentSaveFileName);
			LiveStats.ResetCrewDeaths(__instance.currentSaveFileName);
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "KillPlayerClientRpc")]
	internal static class PlayerDeathPatch
	{
		private static void Postfix(int playerId, int causeOfDeath)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || playerId < 0 || playerId >= instance.allPlayerScripts.Length)
			{
				return;
			}
			PlayerControllerB player = instance.allPlayerScripts[playerId];
			if (player.isPlayerDead)
			{
				string text = ((object)(CauseOfDeath)causeOfDeath/*cast due to .constrained prefix*/).ToString();
				PlayerStats orAdd = LiveStats.Players.GetOrAdd(player.playerClientId, (ulong _) => new PlayerStats
				{
					Name = player.playerUsername,
					DeathCount = LiveStats.GetPersistedDeathCount(player.playerUsername)
				});
				if (orAdd.Alive)
				{
					orAdd.Alive = false;
					orAdd.CauseOfDeath = text;
					orAdd.DeathCount++;
					LiveStats.PersistCrewDeath(player.playerUsername, orAdd.DeathCount, StatsBroadcaster.GetPersistenceSaveFileName());
					string moonName = (((Object)(object)instance.currentLevel != (Object)null) ? instance.currentLevel.PlanetName : null);
					EnemyAttackTracker.TryGetAttacker(playerId, out var enemyName);
					PlayerLifetimeStats.RecordDeath(player.playerUsername, text, moonName, enemyName);
					StatsBroadcaster.Refresh();
				}
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
	internal static class TerminalMessageCommandPatch
	{
		private const string ClearCommand = "message clear";

		private const string AddPrefix = "message add ";

		private const string MessagePrefix = "message ";

		private static bool Prefix(Terminal __instance, ref TerminalNode __result)
		{
			string text = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded);
			text = text.Trim().TrimEnd('.', '!', '?');
			if (string.Equals(text, "message clear", StringComparison.OrdinalIgnoreCase))
			{
				LiveStats.OnScreenMessage = "";
				__result = MakeNode("Message cleared.");
				return false;
			}
			if (text.Length > "message add ".Length && text.Substring(0, "message add ".Length).Equals("message add ", StringComparison.OrdinalIgnoreCase))
			{
				string text2 = text.Substring("message add ".Length).Trim();
				if (string.IsNullOrEmpty(text2))
				{
					return true;
				}
				LiveStats.OnScreenMessage = (string.IsNullOrEmpty(LiveStats.OnScreenMessage) ? text2 : (LiveStats.OnScreenMessage + " " + text2));
				__result = MakeNode("Message updated: \"" + LiveStats.OnScreenMessage + "\"");
				return false;
			}
			if (text.Length > "message ".Length && text.Substring(0, "message ".Length).Equals("message ", StringComparison.OrdinalIgnoreCase))
			{
				string text3 = text.Substring("message ".Length).Trim();
				if (string.IsNullOrEmpty(text3))
				{
					return true;
				}
				LiveStats.OnScreenMessage = text3;
				__result = MakeNode("Message set: \"" + text3 + "\"");
				return false;
			}
			return true;
		}

		private static TerminalNode MakeNode(string text)
		{
			TerminalNode obj = ScriptableObject.CreateInstance<TerminalNode>();
			obj.displayText = text + "\n";
			obj.clearPreviousText = true;
			return obj;
		}
	}
	[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
	internal static class TerminalSellCommandPatch
	{
		private static bool Prefix(Terminal __instance, ref TerminalNode __result)
		{
			string[] array = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded).Trim().Split(new char[1] { ' ' });
			if (array.Length != 2 || array[0].ToLowerInvariant() != "sell")
			{
				return true;
			}
			if (!int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return true;
			}
			TimeOfDay instance = TimeOfDay.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				__result = MakeNode("No active quota to calculate against.\n");
				return false;
			}
			int groupCredits = __instance.groupCredits;
			if (groupCredits >= result)
			{
				__result = MakeNode($"You already have {groupCredits} credits, which meets your {result} credit goal.\n");
				return false;
			}
			int num = RequiredSaleAmount(groupCredits, instance.quotaFulfilled, instance.profitQuota, instance.daysUntilDeadline, result);
			__result = MakeNode($"Sell ${num} worth of scrap to reach {result} credits\n(including the overtime bonus for meeting quota).\n");
			return false;
		}

		private static int RequiredSaleAmount(int currentCredits, int quotaFulfilled, int profitQuota, int daysUntilDeadline, int target)
		{
			int num = (5 * (target - currentCredits) - quotaFulfilled + profitQuota - 75 * daysUntilDeadline) / 6;
			int i;
			for (i = Mathf.Max(0, num - 2); currentCredits + i + OvertimeBonus(quotaFulfilled + i, profitQuota, daysUntilDeadline) < target; i++)
			{
			}
			return i;
		}

		private static int OvertimeBonus(int quotaFulfilledAfterSale, int profitQuota, int daysUntilDeadline)
		{
			return (quotaFulfilledAfterSale - profitQuota) / 5 + 15 * daysUntilDeadline;
		}

		private static TerminalNode MakeNode(string text)
		{
			TerminalNode obj = ScriptableObject.CreateInstance<TerminalNode>();
			obj.displayText = text;
			obj.clearPreviousText = true;
			return obj;
		}
	}
	[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
	internal static class TerminalStatsCommandPatch
	{
		private static bool Prefix(Terminal __instance, ref TerminalNode __result)
		{
			if (string.Equals(__instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded).Trim().TrimEnd('.', '!', '?'), "stats", StringComparison.OrdinalIgnoreCase))
			{
				PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
				string text = (((Object)(object)val != (Object)null) ? val.playerUsername : null);
				__result = MakeNode((!string.IsNullOrEmpty(text)) ? (PlayerLifetimeStats.BuildProfileText(text) + "\n") : "Unable to determine your player name.\n");
				return false;
			}
			return true;
		}

		private static TerminalNode MakeNode(string text)
		{
			TerminalNode obj = ScriptableObject.CreateInstance<TerminalNode>();
			obj.displayText = text;
			obj.clearPreviousText = true;
			return obj;
		}
	}
}
namespace LiveStatsMod.Overlay
{
	internal class OverlayDriver : MonoBehaviour
	{
		private static readonly Regex PhantomPlayerName = new Regex("^Player #\\d+$", RegexOptions.IgnoreCase);

		private TextMeshProUGUI _safetyLine;

		private void Awake()
		{
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
		}

		private void Update()
		{
			try
			{
				Tick();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"Overlay update failed: {arg}");
			}
		}

		private void Tick()
		{
			HandleToggleKeybind();
			if (!Plugin.OverlayEnabled.Value || !LiveStats.InSaveFile)
			{
				return;
			}
			HUDManager instance = HUDManager.Instance;
			if ((Object)(object)instance == (Object)null || instance.controlTipLines == null)
			{
				return;
			}
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if ((Object)(object)val != (Object)null && (Object)(object)val.quickMenuManager != (Object)null && val.quickMenuManager.isMenuOpen)
			{
				ClearLines(instance);
				return;
			}
			string text = "Moon: In Orbit";
			if (LiveStats.IsLanded)
			{
				text = "Moon: " + (string.IsNullOrEmpty(LiveStats.MoonName) ? "-" : LiveStats.MoonName);
				string weatherGlyph = GetWeatherGlyph(GetLineFont(instance, 1), LiveStats.Weather);
				if (!string.IsNullOrEmpty(weatherGlyph))
				{
					text = text + " " + weatherGlyph;
				}
			}
			string text2 = PartySizeLabel();
			string text3 = (string.IsNullOrEmpty(text2) ? $"Day: {LiveStats.DayNumber}" : $"Day: {LiveStats.DayNumber} | {text2}");
			SetLine(instance, 0, text3);
			SetLine(instance, 1, text);
			SetLine(instance, 2, $"Quota {LiveStats.QuotaNumber}: ${LiveStats.ProfitQuota}");
			SetLine(instance, 3, $"Avg Loot/Day: ${LiveStats.AverageScrapPerDay()}");
			UpdateSafetyLine(instance);
		}

		private void UpdateSafetyLine(HUDManager hud)
		{
			EnsureSafetyLine(hud);
			if (!((Object)(object)_safetyLine == (Object)null))
			{
				PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
				ShotgunItem val2 = (ShotgunItem)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
				if ((Object)(object)val2 == (Object)null)
				{
					((Component)_safetyLine).gameObject.SetActive(false);
					return;
				}
				((Component)_safetyLine).gameObject.SetActive(true);
				((TMP_Text)_safetyLine).enableWordWrapping = false;
				((TMP_Text)_safetyLine).text = (val2.safetyOn ? "Turn safety off: [Q]" : "Turn safety on: [Q]");
			}
		}

		private void EnsureSafetyLine(HUDManager hud)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_safetyLine != (Object)null || hud.controlTipLines == null || hud.controlTipLines.Length < 4)
			{
				return;
			}
			TextMeshProUGUI val = hud.controlTipLines[3];
			TextMeshProUGUI val2 = hud.controlTipLines[2];
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
			{
				RectTransform component = ((Component)val).GetComponent<RectTransform>();
				RectTransform component2 = ((Component)val2).GetComponent<RectTransform>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null))
				{
					GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((TMP_Text)val).transform.parent);
					((Object)val3).name = "LiveStats_SafetyLine";
					RectTransform component3 = val3.GetComponent<RectTransform>();
					Vector2 val4 = component.anchoredPosition - component2.anchoredPosition;
					component3.anchoredPosition = component.anchoredPosition + val4;
					_safetyLine = val3.GetComponent<TextMeshProUGUI>();
					((TMP_Text)_safetyLine).text = "";
					val3.SetActive(false);
				}
			}
		}

		private void ClearLines(HUDManager hud)
		{
			for (int i = 0; i < hud.controlTipLines.Length; i++)
			{
				SetLine(hud, i, "");
			}
			if ((Object)(object)_safetyLine != (Object)null)
			{
				((Component)_safetyLine).gameObject.SetActive(false);
			}
		}

		private static void HandleToggleKeybind()
		{
			Keyboard current = Keyboard.current;
			if (current != null && ((ButtonControl)current.oKey).wasPressedThisFrame)
			{
				PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
				if (!((Object)(object)val == (Object)null) && !val.inTerminalMenu && !val.isTypingChat && (!((Object)(object)val.quickMenuManager != (Object)null) || !val.quickMenuManager.isMenuOpen))
				{
					Plugin.OverlayEnabled.Value = !Plugin.OverlayEnabled.Value;
				}
			}
		}

		private static string PartySizeLabel()
		{
			return LiveStats.Players.Values.Count((PlayerStats p) => !p.Disconnected && !PhantomPlayerName.IsMatch((p.Name ?? "").Trim())) switch
			{
				0 => "", 
				1 => "Solo", 
				2 => "Duos", 
				3 => "Trios", 
				_ => "Squads", 
			};
		}

		private static TMP_FontAsset GetLineFont(HUDManager hud, int index)
		{
			if (index >= hud.controlTipLines.Length || (Object)(object)hud.controlTipLines[index] == (Object)null)
			{
				return null;
			}
			return ((TMP_Text)hud.controlTipLines[index]).font;
		}

		private static string GetWeatherGlyph(TMP_FontAsset font, string weather)
		{
			if ((Object)(object)font == (Object)null)
			{
				return "";
			}
			char c;
			switch (weather)
			{
			case "None":
				c = '☀';
				break;
			case "DustClouds":
				c = '☁';
				break;
			case "Rainy":
				c = '☂';
				break;
			case "Stormy":
				c = '⚡';
				break;
			case "Foggy":
				c = '☁';
				break;
			case "Flooded":
				c = '≈';
				break;
			case "Eclipsed":
				c = '☾';
				break;
			default:
				return "";
			}
			if (!font.HasCharacter(c, true, true))
			{
				return "";
			}
			return c.ToString();
		}

		private static void SetLine(HUDManager hud, int index, string text)
		{
			if (index < hud.controlTipLines.Length && !((Object)(object)hud.controlTipLines[index] == (Object)null))
			{
				TextMeshProUGUI obj = hud.controlTipLines[index];
				((TMP_Text)obj).enableWordWrapping = false;
				((TMP_Text)obj).text = text;
			}
		}
	}
	internal static class PauseMenuStatsPanel
	{
		private class StatsPanelRefresher : MonoBehaviour
		{
			private void Update()
			{
				RefreshStatsText();
			}
		}

		private const string ButtonObjectName = "LiveStats_StatsButton";

		private const string PanelObjectName = "LiveStats_StatsPanel";

		private const string ScheduleText = "STREAM SCHEDULE\n\nMonday @ 5pm EST\nTuesday @ 5pm EST\nWednesday @ 5pm EST\nThursday @ 5pm EST\nFriday @ 5pm EST\nSaturday & Sunday - Event Streams\n";

		private static GameObject _panel;

		private static TextMeshProUGUI _statsText;

		private static TextMeshProUGUI _messageTitleText;

		public static void Close()
		{
			if ((Object)(object)_panel != (Object)null)
			{
				_panel.SetActive(false);
			}
		}

		public static void Install(QuickMenuManager quickMenu)
		{
			if (!((Object)(object)quickMenu.mainButtonsPanel == (Object)null) && !((Object)(object)quickMenu.leaveGameConfirmPanel == (Object)null) && !((Object)(object)quickMenu.mainButtonsPanel.transform.Find("LiveStats_StatsButton") != (Object)null))
			{
				BuildPanel(quickMenu);
				BuildButton(quickMenu);
			}
		}

		private static void BuildPanel(QuickMenuManager quickMenu)
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			_panel = Object.Instantiate<GameObject>(quickMenu.leaveGameConfirmPanel, quickMenu.leaveGameConfirmPanel.transform.parent);
			((Object)_panel).name = "LiveStats_StatsPanel";
			_panel.SetActive(false);
			Button[] componentsInChildren = _panel.GetComponentsInChildren<Button>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.Destroy((Object)(object)((Component)componentsInChildren[i]).gameObject);
			}
			TextMeshProUGUI[] array = _panel.GetComponentsInChildren<TextMeshProUGUI>(true).OrderByDescending(delegate(TextMeshProUGUI t)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: 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)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				Rect rect = ((TMP_Text)t).rectTransform.rect;
				float width = ((Rect)(ref rect)).width;
				rect = ((TMP_Text)t).rectTransform.rect;
				return width * ((Rect)(ref rect)).height;
			}).ToArray();
			if (array.Length != 0)
			{
				_statsText = array[0];
				((TMP_Text)_statsText).alignment = (TextAlignmentOptions)257;
				((TMP_Text)_statsText).enableWordWrapping = true;
				((TMP_Text)_statsText).overflowMode = (TextOverflowModes)0;
				((TMP_Text)_statsText).richText = true;
				((TMP_Text)_statsText).text = "";
				RectTransform component = ((Component)_statsText).GetComponent<RectTransform>();
				component.anchoredPosition += new Vector2(0f, ((TMP_Text)_statsText).fontSize * 6f);
				BuildMessageTitle();
				if (Plugin.ShowStreamSchedule.Value)
				{
					BuildScheduleBox();
				}
				_panel.AddComponent<StatsPanelRefresher>();
			}
		}

		private static void BuildMessageTitle()
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = ((Component)_statsText).GetComponent<RectTransform>();
			GameObject obj = Object.Instantiate<GameObject>(((Component)_statsText).gameObject, ((Transform)component).parent);
			((Object)obj).name = "LiveStats_MessageNote";
			_messageTitleText = obj.GetComponent<TextMeshProUGUI>();
			((TMP_Text)_messageTitleText).alignment = (TextAlignmentOptions)1028;
			((TMP_Text)_messageTitleText).enableWordWrapping = true;
			((TMP_Text)_messageTitleText).overflowMode = (TextOverflowModes)0;
			((TMP_Text)_messageTitleText).richText = true;
			((TMP_Text)_messageTitleText).fontStyle = (FontStyles)2;
			((TMP_Text)_messageTitleText).fontSize = ((TMP_Text)_statsText).fontSize * 0.7f;
			((TMP_Text)_messageTitleText).text = "";
			obj.SetActive(false);
			RectTransform component2 = obj.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(1f, 0f);
			component2.anchorMax = new Vector2(1f, 0f);
			component2.pivot = new Vector2(1f, 0f);
			component2.sizeDelta = new Vector2(320f, 80f);
			component2.anchoredPosition = new Vector2(-20f, 20f);
		}

		private static void BuildScheduleBox()
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Object.Instantiate<GameObject>(((Component)_statsText).gameObject, ((TMP_Text)_statsText).transform.parent);
			((Object)obj).name = "LiveStats_ScheduleBox";
			TextMeshProUGUI component = obj.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).alignment = (TextAlignmentOptions)260;
			((TMP_Text)component).enableWordWrapping = true;
			((TMP_Text)component).overflowMode = (TextOverflowModes)0;
			((TMP_Text)component).richText = true;
			((TMP_Text)component).fontSize = ((TMP_Text)_statsText).fontSize * 0.65f;
			((TMP_Text)component).text = "STREAM SCHEDULE\n\nMonday @ 5pm EST\nTuesday @ 5pm EST\nWednesday @ 5pm EST\nThursday @ 5pm EST\nFriday @ 5pm EST\nSaturday & Sunday - Event Streams\n";
			RectTransform component2 = obj.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(1f, 1f);
			component2.anchorMax = new Vector2(1f, 1f);
			component2.pivot = new Vector2(1f, 1f);
			component2.sizeDelta = new Vector2(260f, 160f);
			component2.anchoredPosition = new Vector2(-20f, -20f);
		}

		private static void BuildButton(QuickMenuManager quickMenu)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			Transform transform = quickMenu.mainButtonsPanel.transform;
			Transform val = transform.Find("Quit");
			if (!((Object)(object)val == (Object)null))
			{
				GameObject gameObject = ((Component)val).gameObject;
				GameObject val2 = Object.Instantiate<GameObject>(gameObject, transform);
				((Object)val2).name = "LiveStats_StatsButton";
				Button component = val2.GetComponent<Button>();
				((UnityEventBase)component.onClick).RemoveAllListeners();
				component.onClick = new ButtonClickedEvent();
				((UnityEvent)component.onClick).AddListener((UnityAction)delegate
				{
					RefreshStatsText();
					quickMenu.mainButtonsPanel.SetActive(false);
					quickMenu.EnableUIPanel(_panel);
				});
				TextMeshProUGUI componentInChildren = val2.GetComponentInChildren<TextMeshProUGUI>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					((TMP_Text)componentInChildren).text = "> Stats";
				}
				RepositionButtons(transform, gameObject, val2);
			}
		}

		private static void RepositionButtons(Transform mainButtonsTransform, GameObject quitButton, GameObject clonedButton)
		{
			//IL_0150: 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)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			List<GameObject> source = (from b in ((Component)mainButtonsTransform).GetComponentsInChildren<Button>(true)
				select ((Component)b).gameObject).ToList();
			List<float> list = (from b in source
				where (Object)(object)b != (Object)(object)clonedButton
				select b.GetComponent<RectTransform>() into t
				where (Object)(object)t != (Object)null
				select t.anchoredPosition.y).ToList();
			if (list.Count < 2)
			{
				return;
			}
			float num = list.Zip(list.Skip(1), (float y1, float y2) => Mathf.Abs(y2 - y1)).Min();
			foreach (GameObject item in source.Where((GameObject g) => (Object)(object)g != (Object)(object)quitButton))
			{
				RectTransform component = item.GetComponent<RectTransform>();
				if ((Object)(object)component != (Object)null)
				{
					component.anchoredPosition += new Vector2(0f, num);
				}
			}
			clonedButton.GetComponent<RectTransform>().anchoredPosition = quitButton.GetComponent<RectTransform>().anchoredPosition + new Vector2(0f, num);
		}

		private static void RefreshStatsText()
		{
			if ((Object)(object)_statsText == (Object)null)
			{
				return;
			}
			((TMP_Text)_statsText).text = StatsSummaryText.Build(richText: true);
			if ((Object)(object)_messageTitleText != (Object)null)
			{
				bool flag = !string.IsNullOrEmpty(LiveStats.OnScreenMessage);
				((Component)_messageTitleText).gameObject.SetActive(flag);
				if (flag)
				{
					((TMP_Text)_messageTitleText).text = LiveStats.OnScreenMessage;
				}
			}
		}
	}
}