Decompiled source of GRACEPLUS v1.3.0

GRACEPlus.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BombRushMP.Common;
using BombRushMP.Common.Packets;
using BombRushMP.Plugin;
using BombRushMP.Plugin.Gamemodes;
using HarmonyLib;
using TMPro;
using UnityEngine;
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("GRACEPlus")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("GRACEPlus")]
[assembly: AssemblyTitle("GRACEPlus")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace GRACEPlus
{
	[BepInPlugin("com.snail.graceplus", "GRACEPlus", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class GRACEPlusPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		private static Harmony _harmony;

		private static string _recordsFilePath;

		private static string _customStatsFilePath;

		private static string _mapStatsFolder;

		private static Dictionary<int, double> _bestTimes = new Dictionary<int, double>();

		private static int _customWins = 0;

		private static int _customLosses = 0;

		private static int _customGamesPlayed = 0;

		private static int _customSoloWins = 0;

		private static bool _gameCancelled = false;

		private static int _maxPossibleScore = 0;

		public static ConfigEntry<string> FirstWinMessage;

		public static ConfigEntry<string> NewRecordMessage;

		public static ConfigEntry<string> WinMessage;

		public static ConfigEntry<string> LoseMessage;

		public static ConfigEntry<string> FirstWinColor;

		public static ConfigEntry<string> NewRecordColor;

		public static ConfigEntry<string> WinColor;

		public static ConfigEntry<string> LoseColor;

		public static ConfigEntry<bool> SaveAllMatchResults;

		public static ConfigEntry<bool> TrackMapStats;

		public static ConfigEntry<bool> HideChatDuringRace;

		public static ConfigEntry<bool> HideLobbyUIDuringRace;

		public static ConfigEntry<bool> HideMinimapDuringRace;

		public static ConfigEntry<bool> HideTagCounterDuringRace;

		public static ConfigEntry<string> TagCounterColor;

		public static ConfigEntry<bool> UseCustomTagCounterColor;

		public static ConfigEntry<string> CountdownColor;

		public static ConfigEntry<bool> UseCustomCountdownColor;

		public static ConfigEntry<string> ScoreTextColor;

		public static ConfigEntry<bool> UseCustomScoreTextColor;

		public static ConfigEntry<string> LobbyNameText;

		public static ConfigEntry<string> LobbyNameColor;

		public static ConfigEntry<bool> UseCustomLobbyName;

		public static ConfigEntry<bool> LogEvents;

		private static string _debugLogFilePath;

		private void Awake()
		{
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			FirstWinMessage = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "FirstWinMessage", "FIRST {gamemode}WIN! GRACE Ended IN {time} Seconds on Stage {stage}!", "Message for first win on a stage. Variables: {gamemode}, {time}, {stage}");
			NewRecordMessage = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "NewRecordMessage", "NEW {gamemode}RECORD! GRACE Ended IN {time} Seconds on Stage {stage}! (Previous: {previous}s)", "Message for new record. Variables: {gamemode}, {time}, {stage}, {previous}");
			WinMessage = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "WinMessage", "{gamemode}GRACE Ended IN {time} Seconds! You WON! (Best: {best}s)", "Message for winning without a new record. Variables: {gamemode}, {time}, {best}");
			LoseMessage = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "LoseMessage", "{gamemode}GRACE Ended IN {time} Seconds! You LOST!", "Message for losing a race. Variables: {gamemode}, {time}");
			FirstWinColor = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "FirstWinColor", "yellow", "Color for first win messages (red, green, blue, yellow, white)");
			NewRecordColor = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "NewRecordColor", "yellow", "Color for new record messages (red, green, blue, yellow, white)");
			WinColor = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "WinColor", "green", "Color for win messages (red, green, blue, yellow, white)");
			LoseColor = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "LoseColor", "yellow", "Color for lose messages (red, green, blue, yellow, white)");
			SaveAllMatchResults = ((BaseUnityPlugin)this).Config.Bind<bool>("Features", "SaveAllMatchResults", false, "Save all match results to daily text files in the mod folder");
			TrackMapStats = ((BaseUnityPlugin)this).Config.Bind<bool>("Features", "TrackMapStats", false, "Track detailed statistics for each map including wins, losses, and multiplayer status");
			HideChatDuringRace = ((BaseUnityPlugin)this).Config.Bind<bool>("UI Options", "HideChatDuringRace", false, "Hide BombRushMP's chat UI during GRACE races for a cleaner screen");
			HideLobbyUIDuringRace = ((BaseUnityPlugin)this).Config.Bind<bool>("UI Options", "HideLobbyUIDuringRace", false, "Hide BombRushMP's lobby UI during GRACE races for a cleaner screen");
			HideMinimapDuringRace = ((BaseUnityPlugin)this).Config.Bind<bool>("UI Options", "HideMinimapDuringRace", false, "Hide BombRushMP's minimap during GRACE races for a cleaner screen");
			HideTagCounterDuringRace = ((BaseUnityPlugin)this).Config.Bind<bool>("UI Options", "HideTagCounterDuringRace", false, "Hide the graffiti spots counter during GRACE races for a cleaner screen");
			TagCounterColor = ((BaseUnityPlugin)this).Config.Bind<string>("UI Options", "TagCounterColor", "red", "Color for the graffiti spots counter (red, green, blue, yellow, white, cyan, magenta, black, gray)");
			UseCustomTagCounterColor = ((BaseUnityPlugin)this).Config.Bind<bool>("UI Options", "UseCustomTagCounterColor", false, "Enable custom color for the graffiti spots counter during GRACE races");
			UseCustomCountdownColor = ((BaseUnityPlugin)this).Config.Bind<bool>("UI Options", "UseCustomCountdownColor", false, "Enable custom color for the countdown timer during GRACE races");
			CountdownColor = ((BaseUnityPlugin)this).Config.Bind<string>("UI Options", "CountdownColor", "red", "Color for the countdown timer (red, green, blue, yellow, white, cyan, magenta, black, gray)");
			UseCustomScoreTextColor = ((BaseUnityPlugin)this).Config.Bind<bool>("UI Options", "UseCustomScoreTextColor", false, "Enable custom color for score text in lobby UI");
			ScoreTextColor = ((BaseUnityPlugin)this).Config.Bind<string>("UI Options", "ScoreTextColor", "red", "Color for score text in lobby UI (red, green, blue, yellow, white, cyan, magenta, black, gray)");
			UseCustomLobbyName = ((BaseUnityPlugin)this).Config.Bind<bool>("UI Options", "UseCustomLobbyName", false, "Enable custom lobby name and color");
			LobbyNameText = ((BaseUnityPlugin)this).Config.Bind<string>("UI Options", "LobbyNameText", "GRace Plus Lobby", "Custom text for lobby name");
			LobbyNameColor = ((BaseUnityPlugin)this).Config.Bind<string>("UI Options", "LobbyNameColor", "yellow", "Color for lobby name text (red, green, blue, yellow, white, cyan, magenta, black, gray)");
			string? directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			_recordsFilePath = Path.Combine(directoryName, "grace_records.txt");
			_debugLogFilePath = Path.Combine(directoryName, "debug_log.txt");
			string text = Path.Combine(directoryName, "savefile");
			Directory.CreateDirectory(text);
			_customStatsFilePath = Path.Combine(text, "custom_grace_stats.txt");
			_mapStatsFolder = Path.Combine(directoryName, "Map Stats");
			Directory.CreateDirectory(_mapStatsFolder);
			LoadRecords();
			LoadCustomStats();
			LogEvents = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogEvents", false, "Enable detailed event logging to debug_log.txt for troubleshooting");
			_harmony = new Harmony("com.snail.graceplus");
			_harmony.PatchAll();
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		public static void ShowNotification(string message)
		{
			ChatUI instance = ChatUI.Instance;
			if (instance != null)
			{
				instance.AddMessage(message);
			}
		}

		public static void ShowConfigurableMessage(ConfigEntry<string> messageTemplate, ConfigEntry<string> color, params (string key, string value)[] variables)
		{
			if (messageTemplate != null && color != null)
			{
				string text = messageTemplate.Value;
				for (int i = 0; i < variables.Length; i++)
				{
					(string key, string value) tuple = variables[i];
					string item = tuple.key;
					string item2 = tuple.value;
					string oldValue = "{" + item + "}";
					text = text.Replace(oldValue, item2);
				}
				string text2 = "<color=" + color.Value + ">" + text + "</color>";
				ChatUI instance = ChatUI.Instance;
				if (instance != null)
				{
					instance.AddMessage(text2);
				}
			}
		}

		public static Color ParseColor(string colorName)
		{
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			switch (colorName.ToLower())
			{
			case "red":
				return Color.red;
			case "green":
				return Color.green;
			case "blue":
				return Color.blue;
			case "yellow":
				return Color.yellow;
			case "white":
				return Color.white;
			case "cyan":
				return Color.cyan;
			case "magenta":
				return Color.magenta;
			case "black":
				return Color.black;
			case "gray":
			case "grey":
				return Color.gray;
			default:
				Logger.LogWarning((object)("Unknown color '" + colorName + "', defaulting to white"));
				return Color.white;
			}
		}

		private static void LoadRecords()
		{
			if (!File.Exists(_recordsFilePath))
			{
				return;
			}
			string[] array = File.ReadAllLines(_recordsFilePath);
			foreach (string text in array)
			{
				if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("#"))
				{
					string[] array2 = text.Split(new char[1] { '=' });
					if (array2.Length == 2 && int.TryParse(array2[0].Trim(), out var result) && double.TryParse(array2[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
					{
						_bestTimes[result] = result2;
					}
				}
			}
		}

		private static void SaveRecords()
		{
			List<string> list = new List<string> { "# GRACEPlus Best Times", "# Format: StageID=TimeInSeconds", "# Generated automatically - do not edit manually", "" };
			foreach (KeyValuePair<int, double> bestTime in _bestTimes)
			{
				list.Add(string.Format("{0}={1}", bestTime.Key, bestTime.Value.ToString("F1", CultureInfo.InvariantCulture)));
			}
			File.WriteAllLines(_recordsFilePath, list);
		}

		public static bool CheckAndUpdateBestTime(int stageId, double timeInSeconds, out double? previousBest)
		{
			bool flag = false;
			previousBest = null;
			if (!_bestTimes.ContainsKey(stageId))
			{
				_bestTimes[stageId] = timeInSeconds;
				flag = true;
			}
			else if (timeInSeconds < _bestTimes[stageId])
			{
				previousBest = _bestTimes[stageId];
				_bestTimes[stageId] = timeInSeconds;
				flag = true;
			}
			if (flag)
			{
				SaveRecords();
			}
			return flag;
		}

		public static double? GetBestTime(int stageId)
		{
			if (!_bestTimes.ContainsKey(stageId))
			{
				return null;
			}
			return _bestTimes[stageId];
		}

		public static bool ClearBestTime(int stageId)
		{
			if (_bestTimes.ContainsKey(stageId))
			{
				_bestTimes.Remove(stageId);
				SaveRecords();
				return true;
			}
			return false;
		}

		public static int ClearAllBestTimes()
		{
			int count = _bestTimes.Count;
			if (count > 0)
			{
				_bestTimes.Clear();
				SaveRecords();
			}
			return count;
		}

		private static string GetDailyMatchResultsFilePath()
		{
			string? directoryName = Path.GetDirectoryName(_recordsFilePath);
			string text = DateTime.Now.ToString("yyyy-MM-dd");
			return Path.Combine(directoryName, "Graces_" + text + ".txt");
		}

		public static void SaveMatchResult(int stageId, double timeInSeconds, bool won, bool isTeamMode, bool isNewRecord, double? previousBest)
		{
			if (!SaveAllMatchResults.Value)
			{
				return;
			}
			string dailyMatchResultsFilePath = GetDailyMatchResultsFilePath();
			string text = DateTime.Now.ToString("HH:mm:ss");
			string text2 = (isTeamMode ? "Team GRACE" : "Solo GRACE");
			string text3 = (won ? "WIN" : "LOSS");
			string text4 = "";
			if (won && isNewRecord)
			{
				text4 = ((!previousBest.HasValue) ? " [FIRST WIN!]" : $" [NEW RECORD! Previous: {previousBest.Value:F1}s]");
			}
			else if (won)
			{
				double? bestTime = GetBestTime(stageId);
				if (bestTime.HasValue)
				{
					text4 = $" [Best: {bestTime.Value:F1}s]";
				}
			}
			string text5 = $"[{text}] Stage {stageId} | {text2} | {text3} | {timeInSeconds:F1}s{text4}";
			if (!File.Exists(dailyMatchResultsFilePath))
			{
				List<string> contents = new List<string>
				{
					"# GRACEPlus Daily Match Results",
					$"# Date: {DateTime.Now:yyyy-MM-dd}",
					"# Format: [Time] Stage ID | Gamemode | Result | Duration | Additional Info",
					""
				};
				File.WriteAllLines(dailyMatchResultsFilePath, contents);
			}
			File.AppendAllText(dailyMatchResultsFilePath, text5 + Environment.NewLine);
		}

		private static void LoadCustomStats()
		{
			if (!File.Exists(_customStatsFilePath))
			{
				return;
			}
			string[] array = File.ReadAllLines(_customStatsFilePath);
			foreach (string text in array)
			{
				if (string.IsNullOrWhiteSpace(text) || text.StartsWith("#"))
				{
					continue;
				}
				string[] array2 = text.Split(new char[1] { '=' });
				if (array2.Length != 2)
				{
					continue;
				}
				string text2 = array2[0].Trim();
				if (int.TryParse(array2[1].Trim(), out var result))
				{
					switch (text2)
					{
					case "Wins":
						_customWins = result;
						break;
					case "Losses":
						_customLosses = result;
						break;
					case "GamesPlayed":
						_customGamesPlayed = result;
						break;
					case "SoloWins":
						_customSoloWins = result;
						break;
					}
				}
			}
		}

		private static void SaveCustomStats()
		{
			List<string> contents = new List<string>
			{
				"# GRACEPlus Custom Statistics",
				"# Format: StatName=Value",
				"# Generated automatically - do not edit manually",
				"",
				$"Wins={_customWins}",
				$"Losses={_customLosses}",
				$"GamesPlayed={_customGamesPlayed}",
				$"SoloWins={_customSoloWins}"
			};
			File.WriteAllLines(_customStatsFilePath, contents);
		}

		public static void IncrementCustomWins(bool isSolo)
		{
			if (isSolo)
			{
				_customSoloWins++;
			}
			else
			{
				_customWins++;
			}
			_customGamesPlayed++;
			SaveCustomStats();
		}

		public static void IncrementCustomLosses()
		{
			_customLosses++;
			_customGamesPlayed++;
			SaveCustomStats();
		}

		public static (int wins, int losses, int gamesPlayed, int soloWins) GetCustomStats()
		{
			return (_customWins, _customLosses, _customGamesPlayed, _customSoloWins);
		}

		public static void SetGameCancelled(bool cancelled)
		{
			_gameCancelled = cancelled;
		}

		public static bool IsGameCancelled()
		{
			return _gameCancelled;
		}

		public static void SetMaxPossibleScore(int maxScore)
		{
			_maxPossibleScore = maxScore;
		}

		public static int GetMaxPossibleScore()
		{
			return _maxPossibleScore;
		}

		public static void ResetMaxPossibleScore()
		{
			_maxPossibleScore = 0;
		}

		public static void SaveWinTime(int stageId, double timeInSeconds)
		{
			if (TrackMapStats.Value)
			{
				string path = Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt");
				string arg = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
				string text = $"{arg},{timeInSeconds:F1}";
				File.AppendAllText(path, text + Environment.NewLine);
			}
		}

		public static void SaveMapStats(int stageId, double timeInSeconds, bool won, bool isMultiplayer)
		{
			if (TrackMapStats.Value)
			{
				string path = Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt");
				string text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
				string text2 = (won ? "WIN" : "LOSS");
				string text3 = (isMultiplayer ? "MULTIPLAYER" : "SOLO");
				string text4 = $"{text},{timeInSeconds:F1},{text2},{text3}";
				if (!File.Exists(path))
				{
					List<string> contents = new List<string>
					{
						"# GRACEPlus Map Statistics",
						$"# Stage: {stageId}",
						"# Format: Timestamp,Time,Result,GameType",
						"# Result: WIN or LOSS",
						"# GameType: MULTIPLAYER or SOLO",
						""
					};
					File.WriteAllLines(path, contents);
				}
				File.AppendAllText(path, text4 + Environment.NewLine);
			}
		}

		public static double? GetAverageTime(int stageId)
		{
			if (!TrackMapStats.Value)
			{
				return null;
			}
			string path = Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt");
			if (!File.Exists(path))
			{
				return null;
			}
			string[] array = File.ReadAllLines(path);
			List<double> list = new List<double>();
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("#"))
				{
					string[] array3 = text.Split(new char[1] { ',' });
					if (array3.Length >= 3 && double.TryParse(array3[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && array3[2] == "WIN")
					{
						list.Add(result);
					}
				}
			}
			if (list.Count <= 0)
			{
				return null;
			}
			return list.Average();
		}

		public static int GetWinCount(int stageId)
		{
			if (!TrackMapStats.Value)
			{
				return 0;
			}
			string path = Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt");
			if (!File.Exists(path))
			{
				return 0;
			}
			string[] array = File.ReadAllLines(path);
			int num = 0;
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("#"))
				{
					string[] array3 = text.Split(new char[1] { ',' });
					if (array3.Length >= 3 && array3[2] == "WIN")
					{
						num++;
					}
				}
			}
			return num;
		}

		public static (int multiplayerWins, int multiplayerLosses, int soloGames, double multiplayerWinRatio) GetMapStats(int stageId)
		{
			if (!TrackMapStats.Value)
			{
				return (0, 0, 0, 0.0);
			}
			string path = Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt");
			if (!File.Exists(path))
			{
				return (0, 0, 0, 0.0);
			}
			string[] array = File.ReadAllLines(path);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (string.IsNullOrWhiteSpace(text) || text.StartsWith("#"))
				{
					continue;
				}
				string[] array3 = text.Split(new char[1] { ',' });
				if (array3.Length < 4)
				{
					continue;
				}
				string text2 = array3[2];
				string text3 = array3[3];
				if (text3 == "MULTIPLAYER")
				{
					if (text2 == "WIN")
					{
						num++;
					}
					else if (text2 == "LOSS")
					{
						num2++;
					}
				}
				else if (text3 == "SOLO")
				{
					num3++;
				}
			}
			double item = 0.0;
			int num4 = num + num2;
			if (num4 > 0)
			{
				item = (double)num / (double)num4 * 100.0;
			}
			return (num, num2, num3, item);
		}

		public static bool HasMapStatsFile(int stageId)
		{
			return File.Exists(Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt"));
		}

		public static bool ClearMapStats(int stageId)
		{
			string path = Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt");
			if (File.Exists(path))
			{
				File.Delete(path);
				return true;
			}
			return false;
		}

		public static int ClearAllMapStats()
		{
			if (!Directory.Exists(_mapStatsFolder))
			{
				return 0;
			}
			string[] files = Directory.GetFiles(_mapStatsFolder, "Stage_*.txt");
			int num = 0;
			string[] array = files;
			foreach (string path in array)
			{
				try
				{
					File.Delete(path);
					num++;
				}
				catch
				{
				}
			}
			return num;
		}

		public static bool ClearCustomStats()
		{
			if (File.Exists(_customStatsFilePath))
			{
				File.Delete(_customStatsFilePath);
				_customWins = 0;
				_customLosses = 0;
				_customGamesPlayed = 0;
				_customSoloWins = 0;
				return true;
			}
			return false;
		}

		public static void DebugLog(string message)
		{
			if (!LogEvents.Value)
			{
				return;
			}
			try
			{
				string text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
				string text2 = "[" + text + "] " + message;
				File.AppendAllText(_debugLogFilePath, text2 + Environment.NewLine);
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Failed to write debug log: " + ex.Message));
			}
		}

		public static void ClearDebugLog()
		{
			try
			{
				if (File.Exists(_debugLogFilePath))
				{
					File.Delete(_debugLogFilePath);
				}
				DebugLog("=== Debug Log Started ===");
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Failed to clear debug log: " + ex.Message));
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.snail.graceplus";

		public const string PLUGIN_NAME = "GRACEPlus";

		public const string PLUGIN_VERSION = "1.0.0";
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "GRACEPlus";

		public const string PLUGIN_NAME = "GRACEPlus";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace GRACEPlus.Patches
{
	[HarmonyPatch(typeof(ChatUI), "ProcessLocalCommand")]
	public static class ChatCommandPatch
	{
		private static bool Prefix(ChatUI __instance, string message)
		{
			if (string.IsNullOrEmpty(message))
			{
				return true;
			}
			switch (message.ToLower())
			{
			case "/timeclear":
				HandleTimeClearCommand();
				return false;
			case "/timeclearall":
				HandleTimeClearAllCommand();
				return false;
			case "/showbest":
				HandleShowBestCommand();
				return false;
			case "/gracestats":
				HandleGraceStatsCommand();
				return false;
			case "/avgtime":
				HandleAvgTimeCommand();
				return false;
			case "/mapstats":
				HandleMapStatsCommand();
				return false;
			case "/clearmapstats":
				HandleClearMapStatsCommand();
				return false;
			case "/clearmapstatsall":
				HandleClearMapStatsAllCommand();
				return false;
			case "/gracestatsclear":
				HandleGraceStatsClearCommand();
				return false;
			case "/gracehelp":
				HandleGraceHelpCommand();
				return false;
			default:
				return true;
			}
		}

		private static void HandleTimeClearCommand()
		{
			//IL_0036: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Invalid comparison between Unknown and I4
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			ClientController instance = ClientController.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				ClientLobbyManager clientLobbyManager = instance.ClientLobbyManager;
				obj = ((clientLobbyManager != null) ? clientLobbyManager.CurrentLobby : null);
			}
			Lobby val = (Lobby)obj;
			if (val != null)
			{
				int stage = val.LobbyState.Stage;
				GamemodeIDs gamemode = val.LobbyState.Gamemode;
				if ((int)gamemode == 1 || (int)gamemode == 2)
				{
					double? bestTime = GRACEPlusPlugin.GetBestTime(stage);
					if (bestTime.HasValue)
					{
						if (GRACEPlusPlugin.ClearBestTime(stage))
						{
							string arg = (((int)gamemode == 2) ? "Team GRACE" : "GRACE");
							GRACEPlusPlugin.ShowNotification($"<color=red>Cleared {arg} record for Stage {stage}! (Was: {bestTime.Value:F1}s)</color>");
						}
						else
						{
							GRACEPlusPlugin.ShowNotification("<color=red>Failed to clear record!</color>");
						}
					}
					else
					{
						GRACEPlusPlugin.ShowNotification($"<color=yellow>No record found for Stage {stage} to clear!</color>");
					}
				}
				else
				{
					GRACEPlusPlugin.ShowNotification("<color=red>/timeclear can only be used in GRACE lobbies!</color>");
				}
			}
			else
			{
				GRACEPlusPlugin.ShowNotification("<color=red>You must be in a lobby to use /timeclear!</color>");
			}
		}

		private static void HandleTimeClearAllCommand()
		{
			int num = GRACEPlusPlugin.ClearAllBestTimes();
			if (num > 0)
			{
				GRACEPlusPlugin.ShowNotification($"<color=red>Cleared ALL GRACE records! ({num} records deleted)</color>");
			}
			else
			{
				GRACEPlusPlugin.ShowNotification("<color=yellow>No records found to clear!</color>");
			}
		}

		private static void HandleShowBestCommand()
		{
			ClientController instance = ClientController.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				ClientLobbyManager clientLobbyManager = instance.ClientLobbyManager;
				obj = ((clientLobbyManager != null) ? clientLobbyManager.CurrentLobby : null);
			}
			Lobby val = (Lobby)obj;
			if (val != null)
			{
				int stage = val.LobbyState.Stage;
				double? bestTime = GRACEPlusPlugin.GetBestTime(stage);
				if (bestTime.HasValue)
				{
					GRACEPlusPlugin.ShowNotification($"<color=green>Your best time on Stage {stage}: {bestTime.Value:F1}s</color>");
				}
				else
				{
					GRACEPlusPlugin.ShowNotification("<color=yellow>No best time saved yet for this map</color>");
				}
			}
			else
			{
				GRACEPlusPlugin.ShowNotification("<color=red>You must be in a lobby to use /showbest!</color>");
			}
		}

		private static void HandleGraceStatsCommand()
		{
			MPStats stats = MPSaveData.Instance.Stats;
			uint value = 0u;
			uint value2 = 0u;
			uint value3 = 0u;
			stats.GamemodesWon.TryGetValue((GamemodeIDs)1, out value);
			stats.GamemodesPlayed.TryGetValue((GamemodeIDs)1, out value2);
			stats.GamemodesPlayedAlone.TryGetValue((GamemodeIDs)1, out value3);
			uint elitesPlayedAgainst = stats.ElitesPlayedAgainst;
			uint elitesBeaten = stats.ElitesBeaten;
			GRACEPlusPlugin.ShowNotification("<color=yellow>=== ACN Stats: ===</color>");
			GRACEPlusPlugin.ShowNotification($"<color=yellow>GRACE Wins: {value}</color>");
			GRACEPlusPlugin.ShowNotification($"<color=yellow>GRACE Games Played: {value2}</color>");
			GRACEPlusPlugin.ShowNotification($"<color=yellow>GRACE Solo Games: {value3}</color>");
			GRACEPlusPlugin.ShowNotification($"<color=yellow>Elites Played Against: {elitesPlayedAgainst}</color>");
			GRACEPlusPlugin.ShowNotification($"<color=yellow>Elites Beaten: {elitesBeaten}</color>");
			(int wins, int losses, int gamesPlayed, int soloWins) customStats = GRACEPlusPlugin.GetCustomStats();
			int item = customStats.wins;
			int item2 = customStats.losses;
			int num = item + item2;
			double num2 = 0.0;
			if (num > 0)
			{
				num2 = (double)item / (double)num * 100.0;
			}
			GRACEPlusPlugin.ShowNotification("<color=green>=== GRACEPlus Custom Stats: ===</color>");
			GRACEPlusPlugin.ShowNotification($"<color=green>Multiplayer Wins: {item}</color>");
			GRACEPlusPlugin.ShowNotification($"<color=green>Multiplayer Losses: {item2}</color>");
			GRACEPlusPlugin.ShowNotification($"<color=green>Multiplayer Games: {num}</color>");
			GRACEPlusPlugin.ShowNotification($"<color=green>Multiplayer Win Ratio: {num2:F1}%</color>");
		}

		private static void HandleAvgTimeCommand()
		{
			if (!GRACEPlusPlugin.TrackMapStats.Value)
			{
				GRACEPlusPlugin.ShowNotification("<color=red>Map statistics tracking is disabled! Enable 'Track Map Stats' in config.</color>");
				return;
			}
			ClientController instance = ClientController.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				ClientLobbyManager clientLobbyManager = instance.ClientLobbyManager;
				obj = ((clientLobbyManager != null) ? clientLobbyManager.CurrentLobby : null);
			}
			Lobby val = (Lobby)obj;
			if (val != null)
			{
				int stage = val.LobbyState.Stage;
				double? averageTime = GRACEPlusPlugin.GetAverageTime(stage);
				int winCount = GRACEPlusPlugin.GetWinCount(stage);
				if (averageTime.HasValue && winCount > 0)
				{
					GRACEPlusPlugin.ShowNotification($"<color=green>Stage {stage} Average: {averageTime.Value:F1}s ({winCount} wins)</color>");
				}
				else
				{
					GRACEPlusPlugin.ShowNotification($"<color=yellow>No win times recorded yet for Stage {stage}</color>");
				}
			}
			else
			{
				GRACEPlusPlugin.ShowNotification("<color=red>You must be in a lobby to use /avgtime!</color>");
			}
		}

		private static void HandleMapStatsCommand()
		{
			ClientController instance = ClientController.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				ClientLobbyManager clientLobbyManager = instance.ClientLobbyManager;
				obj = ((clientLobbyManager != null) ? clientLobbyManager.CurrentLobby : null);
			}
			Lobby val = (Lobby)obj;
			if (val != null)
			{
				int stage = val.LobbyState.Stage;
				if (!GRACEPlusPlugin.TrackMapStats.Value && !GRACEPlusPlugin.HasMapStatsFile(stage))
				{
					GRACEPlusPlugin.ShowNotification("<color=yellow>Enable Map Stat Tracking in config, run some games on this map, and then you will have stats to see here</color>");
					return;
				}
				double? averageTime = GRACEPlusPlugin.GetAverageTime(stage);
				double? bestTime = GRACEPlusPlugin.GetBestTime(stage);
				var (num, num2, num3, num4) = GRACEPlusPlugin.GetMapStats(stage);
				if (averageTime.HasValue || bestTime.HasValue || num > 0 || num2 > 0 || num3 > 0)
				{
					GRACEPlusPlugin.ShowNotification($"<color=green>=== Stage {stage} Statistics ===</color>");
					if (averageTime.HasValue)
					{
						GRACEPlusPlugin.ShowNotification($"<color=green>Avg Win Time: {averageTime.Value:F1}s</color>");
					}
					else
					{
						GRACEPlusPlugin.ShowNotification("<color=yellow>Avg Win Time: No wins recorded</color>");
					}
					if (bestTime.HasValue)
					{
						GRACEPlusPlugin.ShowNotification($"<color=green>Best Win Time: {bestTime.Value:F1}s</color>");
					}
					else
					{
						GRACEPlusPlugin.ShowNotification("<color=yellow>Best Win Time: No record set</color>");
					}
					if (num > 0 || num2 > 0)
					{
						GRACEPlusPlugin.ShowNotification($"<color=green>Multiplayer Win Ratio: {num4:F1}%</color>");
						GRACEPlusPlugin.ShowNotification($"<color=green>Multiplayer Wins: {num}</color>");
						GRACEPlusPlugin.ShowNotification($"<color=green>Multiplayer Losses: {num2}</color>");
					}
					else
					{
						GRACEPlusPlugin.ShowNotification("<color=yellow>Multiplayer Win Ratio: No multiplayer games</color>");
						GRACEPlusPlugin.ShowNotification("<color=yellow>Multiplayer Wins: 0</color>");
						GRACEPlusPlugin.ShowNotification("<color=yellow>Multiplayer Losses: 0</color>");
					}
					GRACEPlusPlugin.ShowNotification($"<color=green>Solo Games: {num3}</color>");
				}
				else
				{
					GRACEPlusPlugin.ShowNotification("<color=yellow>Enable Map Stat Tracking in config, run some games on this map, and then you will have stats to see here</color>");
				}
			}
			else
			{
				GRACEPlusPlugin.ShowNotification("<color=red>You must be in a lobby to use /mapstats!</color>");
			}
		}

		private static void HandleClearMapStatsCommand()
		{
			ClientController instance = ClientController.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				ClientLobbyManager clientLobbyManager = instance.ClientLobbyManager;
				obj = ((clientLobbyManager != null) ? clientLobbyManager.CurrentLobby : null);
			}
			Lobby val = (Lobby)obj;
			if (val != null)
			{
				int stage = val.LobbyState.Stage;
				if (GRACEPlusPlugin.ClearMapStats(stage))
				{
					GRACEPlusPlugin.ShowNotification($"<color=red>Cleared map statistics for Stage {stage}!</color>");
				}
				else
				{
					GRACEPlusPlugin.ShowNotification("<color=yellow>There is no map stats to clear</color>");
				}
			}
			else
			{
				GRACEPlusPlugin.ShowNotification("<color=red>You must be in a lobby to use /clearmapstats!</color>");
			}
		}

		private static void HandleClearMapStatsAllCommand()
		{
			int num = GRACEPlusPlugin.ClearAllMapStats();
			if (num > 0)
			{
				GRACEPlusPlugin.ShowNotification($"<color=red>Cleared ALL map statistics! ({num} files deleted)</color>");
			}
			else
			{
				GRACEPlusPlugin.ShowNotification("<color=yellow>There are no map stats to clear</color>");
			}
		}

		private static void HandleGraceStatsClearCommand()
		{
			if (GRACEPlusPlugin.ClearCustomStats())
			{
				GRACEPlusPlugin.ShowNotification("<color=red>Cleared all custom GRACE statistics!</color>");
			}
			else
			{
				GRACEPlusPlugin.ShowNotification("<color=yellow>No custom GRACE statistics to clear</color>");
			}
		}

		private static void HandleGraceHelpCommand()
		{
			GRACEPlusPlugin.ShowNotification("<color=green>=== GRACEPlus Commands ===</color>");
			GRACEPlusPlugin.ShowNotification("<color=white>/showbest - Show your best time for current stage</color>");
			GRACEPlusPlugin.ShowNotification("<color=white>/timeclear - Clear best time for current stage</color>");
			GRACEPlusPlugin.ShowNotification("<color=white>/timeclearall - Clear all saved best times</color>");
			GRACEPlusPlugin.ShowNotification("<color=white>/gracestats - Show lifetime GRACE statistics</color>");
			GRACEPlusPlugin.ShowNotification("<color=white>/gracestatsclear - Clear custom statistics</color>");
			GRACEPlusPlugin.ShowNotification("<color=white>/avgtime - Show average win time for current stage</color>");
			GRACEPlusPlugin.ShowNotification("<color=white>/mapstats - Show detailed stats for current stage</color>");
			GRACEPlusPlugin.ShowNotification("<color=white>/clearmapstats - Clear map stats for current stage</color>");
			GRACEPlusPlugin.ShowNotification("<color=white>/clearmapstatsall - Clear all map statistics</color>");
			GRACEPlusPlugin.ShowNotification("<color=white>/gracehelp - Show this help message</color>");
		}
	}
	[HarmonyPatch(typeof(GraffitiRace), "OnEnd")]
	internal class GraffitiRaceCancellationPatch
	{
		private static void Prefix(GraffitiRace __instance, bool cancelled)
		{
			GRACEPlusPlugin.SetGameCancelled(cancelled);
			GRACEPlusPlugin.DebugLog($"EVENT: Race ending - Cancelled: {cancelled}");
		}
	}
	[HarmonyPatch(typeof(GraffitiRace), "OnPacketReceived_InGame")]
	internal class GraffitiRaceTimerPatch
	{
		private static DateTime raceStartTime;

		private static bool isRaceActive;

		private static void Postfix(GraffitiRace __instance, Packets packetId, Packet packet)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)packetId == 19 && !isRaceActive)
			{
				raceStartTime = DateTime.Now;
				isRaceActive = true;
				GRACEPlusPlugin.SetGameCancelled(cancelled: false);
				GRACEPlusPlugin.DebugLog("EVENT: Race started (ServerGamemodeBegin received)");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GraffitiRace), "OnEnd")]
		private static void OnEnd_Postfix(GraffitiRace __instance)
		{
			if (!isRaceActive)
			{
				return;
			}
			double num = Math.Round((DateTime.Now - raceStartTime).TotalSeconds, 1);
			isRaceActive = false;
			GRACEPlusPlugin.DebugLog($"EVENT: Race ended - Duration: {num}s");
			ClientController instance = ClientController.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				ClientLobbyManager clientLobbyManager = instance.ClientLobbyManager;
				obj = ((clientLobbyManager != null) ? clientLobbyManager.CurrentLobby : null);
			}
			if (obj != null)
			{
				Lobby currentLobby = instance.ClientLobbyManager.CurrentLobby;
				ushort localID = instance.LocalID;
				int stage = currentLobby.LobbyState.Stage;
				GRACEPlusPlugin.DebugLog($"INFO: Local Player ID: {localID}, Stage ID: {stage}");
				GRACEPlusPlugin.DebugLog($"INFO: Team Based: {((Gamemode)__instance).TeamBased}");
				bool flag = false;
				int maxPossibleScore = GRACEPlusPlugin.GetMaxPossibleScore();
				GRACEPlusPlugin.DebugLog($"INFO: Max Possible Score: {maxPossibleScore}");
				if (maxPossibleScore > 0)
				{
					if (((Gamemode)__instance).TeamBased)
					{
						if (currentLobby.LobbyState.Players.ContainsKey(localID))
						{
							byte team = currentLobby.LobbyState.Players[localID].Team;
							float scoreForTeam = currentLobby.LobbyState.GetScoreForTeam(team);
							GRACEPlusPlugin.DebugLog($"INFO: User Team: {team}, Team Score: {scoreForTeam}");
							flag = scoreForTeam >= (float)maxPossibleScore && scoreForTeam > 0f;
							GRACEPlusPlugin.DebugLog($"CALC: userTeamScore ({scoreForTeam}) >= maxPossibleScore ({maxPossibleScore}) && userTeamScore > 0 = {flag}");
						}
						else
						{
							GRACEPlusPlugin.DebugLog($"ERROR: Local player ID {localID} not found in lobby players!");
						}
					}
					else if (currentLobby.LobbyState.Players.ContainsKey(localID))
					{
						float score = currentLobby.LobbyState.Players[localID].Score;
						GRACEPlusPlugin.DebugLog($"INFO: User Score: {score}");
						flag = score >= (float)maxPossibleScore && score > 0f;
						GRACEPlusPlugin.DebugLog($"CALC: userScore ({score}) >= maxPossibleScore ({maxPossibleScore}) && userScore > 0 = {flag}");
					}
					else
					{
						GRACEPlusPlugin.DebugLog($"ERROR: Local player ID {localID} not found in lobby players!");
					}
				}
				else
				{
					flag = false;
					GRACEPlusPlugin.DebugLog("CALC: maxPossibleScore is 0, setting userWon = false");
				}
				GRACEPlusPlugin.DebugLog($"RESULT: User Won = {flag}");
				string text = (((Gamemode)__instance).TeamBased ? "Team " : "");
				if (flag)
				{
					double? previousBest;
					bool flag2 = GRACEPlusPlugin.CheckAndUpdateBestTime(stage, num, out previousBest);
					GRACEPlusPlugin.SaveMatchResult(stage, num, won: true, ((Gamemode)__instance).TeamBased, flag2, previousBest);
					if (GRACEPlusPlugin.TrackMapStats.Value)
					{
						bool isMultiplayer = currentLobby.LobbyState.Players.Count > 1;
						GRACEPlusPlugin.SaveMapStats(stage, num, won: true, isMultiplayer);
					}
					if (!GRACEPlusPlugin.IsGameCancelled())
					{
						GRACEPlusPlugin.IncrementCustomWins(currentLobby.LobbyState.Players.Count == 1);
					}
					if (flag2)
					{
						if (previousBest.HasValue)
						{
							GRACEPlusPlugin.ShowConfigurableMessage(GRACEPlusPlugin.NewRecordMessage, GRACEPlusPlugin.NewRecordColor, ("gamemode", text.ToUpper()), ("time", num.ToString()), ("stage", stage.ToString()), ("previous", previousBest.Value.ToString("F1")));
						}
						else
						{
							GRACEPlusPlugin.ShowConfigurableMessage(GRACEPlusPlugin.FirstWinMessage, GRACEPlusPlugin.FirstWinColor, ("gamemode", text.ToUpper()), ("time", num.ToString()), ("stage", stage.ToString()));
						}
					}
					else
					{
						double? bestTime = GRACEPlusPlugin.GetBestTime(stage);
						GRACEPlusPlugin.ShowConfigurableMessage(GRACEPlusPlugin.WinMessage, GRACEPlusPlugin.WinColor, ("gamemode", text), ("time", num.ToString()), ("best", bestTime?.ToString("F1") ?? "N/A"));
					}
				}
				else
				{
					GRACEPlusPlugin.SaveMatchResult(stage, num, won: false, ((Gamemode)__instance).TeamBased, isNewRecord: false, null);
					if (GRACEPlusPlugin.TrackMapStats.Value)
					{
						bool isMultiplayer2 = currentLobby.LobbyState.Players.Count > 1;
						GRACEPlusPlugin.SaveMapStats(stage, num, won: false, isMultiplayer2);
					}
					if (!GRACEPlusPlugin.IsGameCancelled())
					{
						GRACEPlusPlugin.IncrementCustomLosses();
					}
					GRACEPlusPlugin.ShowConfigurableMessage(GRACEPlusPlugin.LoseMessage, GRACEPlusPlugin.LoseColor, ("gamemode", text), ("time", num.ToString()));
				}
			}
			else
			{
				string arg = (((Gamemode)__instance).TeamBased ? "Team " : "");
				GRACEPlusPlugin.ShowNotification($"<color=green>{arg}GRACE Ended IN {num} Seconds!</color>");
				GRACEPlusPlugin.DebugLog("INFO: No lobby data available, showing basic message");
			}
			GRACEPlusPlugin.ResetMaxPossibleScore();
			GRACEPlusPlugin.DebugLog("EVENT: Max possible score reset to 0");
		}
	}
	[HarmonyPatch(typeof(GraffitiRace), "OnReceive_GraffitiRaceData")]
	internal class GraffitiRaceDataReceivePatch
	{
		private static void Postfix(GraffitiRace __instance, ClientGraffitiRaceGSpots packet)
		{
			int num = GRACEPlusPlugin.GetMaxPossibleScore() + packet.GraffitiSpots.Count;
			GRACEPlusPlugin.SetMaxPossibleScore(num);
			GRACEPlusPlugin.DebugLog($"EVENT: OnReceive_GraffitiRaceData - Added {packet.GraffitiSpots.Count} spots, Total max score: {num}");
		}
	}
	[HarmonyPatch(typeof(LobbyUI), "UpdateUI")]
	internal class LobbyUIUpdatePatch
	{
		private static void Postfix(LobbyUI __instance)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FieldInfo field = typeof(LobbyUI).GetField("_canvas", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field == null || (Object)/*isinst with value type is only supported in some contexts*/ == (Object)null || !GRACEPlusPlugin.UseCustomLobbyName.Value)
				{
					return;
				}
				FieldInfo field2 = typeof(LobbyUI).GetField("_lobbyName", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field2 != null)
				{
					object? value = field2.GetValue(__instance);
					TextMeshProUGUI val = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null);
					if ((Object)(object)val != (Object)null)
					{
						((TMP_Text)val).text = GRACEPlusPlugin.LobbyNameText.Value;
						((Graphic)val).color = GRACEPlusPlugin.ParseColor(GRACEPlusPlugin.LobbyNameColor.Value);
					}
				}
			}
			catch (Exception ex)
			{
				GRACEPlusPlugin.Logger.LogError((object)("Error in LobbyUI UpdateUI patch: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(LobbyPlayerUI), "SetPlayer")]
	internal class LobbyPlayerUISetPlayerPatch
	{
		private static void Postfix(LobbyPlayerUI __instance)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FieldInfo field = typeof(LobbyPlayerUI).GetField("_score", BindingFlags.Instance | BindingFlags.NonPublic);
				if (GRACEPlusPlugin.UseCustomScoreTextColor.Value && field != null)
				{
					object? value = field.GetValue(__instance);
					TextMeshProUGUI val = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null);
					if ((Object)(object)val != (Object)null)
					{
						((Graphic)val).color = GRACEPlusPlugin.ParseColor(GRACEPlusPlugin.ScoreTextColor.Value);
					}
				}
			}
			catch (Exception ex)
			{
				GRACEPlusPlugin.Logger.LogError((object)("Error in LobbyPlayerUI SetPlayer patch: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(LobbyPlayerUI), "SetTeam")]
	internal class LobbyPlayerUISetTeamPatch
	{
		private static void Postfix(LobbyPlayerUI __instance)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FieldInfo field = typeof(LobbyPlayerUI).GetField("_score", BindingFlags.Instance | BindingFlags.NonPublic);
				if (GRACEPlusPlugin.UseCustomScoreTextColor.Value && field != null)
				{
					object? value = field.GetValue(__instance);
					TextMeshProUGUI val = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null);
					if ((Object)(object)val != (Object)null)
					{
						((Graphic)val).color = GRACEPlusPlugin.ParseColor(GRACEPlusPlugin.ScoreTextColor.Value);
					}
				}
			}
			catch (Exception ex)
			{
				GRACEPlusPlugin.Logger.LogError((object)("Error in LobbyPlayerUI SetTeam patch: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(GraffitiRace), "OnPacketReceived_InGame")]
	internal class UIHidingOnStartPatch
	{
		private static bool _uiHidden = false;

		private static bool _originalChatVisible = true;

		private static bool _originalLobbyVisible = true;

		private static bool _originalMinimapVisible = true;

		private static bool _originalTimerVisible = true;

		private static Color _originalTimerColor = Color.white;

		private static Color _originalCountdownColor = Color.white;

		private static void Postfix(GraffitiRace __instance, Packets packetId, Packet packet)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)packetId == 19 && !_uiHidden)
			{
				HideUIElements();
				_uiHidden = true;
			}
		}

		public static bool IsUIHidden()
		{
			return _uiHidden;
		}

		private static void HideUIElements()
		{
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (GRACEPlusPlugin.HideChatDuringRace.Value && (Object)(object)ChatUI.Instance != (Object)null)
				{
					FieldInfo field = typeof(ChatUI).GetField("_chatWindow", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field != null)
					{
						object? value = field.GetValue(ChatUI.Instance);
						GameObject val = (GameObject)((value is GameObject) ? value : null);
						if ((Object)(object)val != (Object)null)
						{
							GameObject gameObject = ((Component)val.transform.parent).gameObject;
							if ((Object)(object)gameObject != (Object)null)
							{
								_originalChatVisible = gameObject.activeSelf;
								gameObject.SetActive(false);
							}
						}
					}
				}
				if (GRACEPlusPlugin.HideLobbyUIDuringRace.Value && (Object)(object)LobbyUI.Instance != (Object)null)
				{
					FieldInfo field2 = typeof(LobbyUI).GetField("_canvas", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field2 != null)
					{
						object? value2 = field2.GetValue(LobbyUI.Instance);
						GameObject val2 = (GameObject)((value2 is GameObject) ? value2 : null);
						if ((Object)(object)val2 != (Object)null)
						{
							_originalLobbyVisible = val2.activeSelf;
							val2.SetActive(false);
						}
					}
				}
				if (GRACEPlusPlugin.HideMinimapDuringRace.Value && (Object)(object)MPMapController.Instance != (Object)null)
				{
					FieldInfo field3 = typeof(MPMapController).GetField("_mapUI", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field3 != null)
					{
						object value3 = field3.GetValue(MPMapController.Instance);
						if (value3 != null)
						{
							object obj = ((value3 is Component) ? value3 : null);
							GameObject val3 = ((obj != null) ? ((Component)obj).gameObject : null);
							if ((Object)(object)val3 != (Object)null)
							{
								_originalMinimapVisible = val3.activeSelf;
								val3.SetActive(false);
							}
						}
					}
				}
				if (GRACEPlusPlugin.HideTagCounterDuringRace.Value && (Object)(object)TimerUI.Instance != (Object)null)
				{
					FieldInfo field4 = typeof(TimerUI).GetField("_canvas", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field4 != null)
					{
						object? value4 = field4.GetValue(TimerUI.Instance);
						GameObject val4 = (GameObject)((value4 is GameObject) ? value4 : null);
						if ((Object)(object)val4 != (Object)null)
						{
							_originalTimerVisible = val4.activeSelf;
							val4.SetActive(false);
						}
					}
				}
				if (GRACEPlusPlugin.UseCustomTagCounterColor.Value && (Object)(object)TimerUI.Instance != (Object)null)
				{
					FieldInfo field5 = typeof(TimerUI).GetField("_label", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field5 != null)
					{
						object value5 = field5.GetValue(TimerUI.Instance);
						if (value5 != null)
						{
							PropertyInfo property = value5.GetType().GetProperty("color");
							if (property != null)
							{
								_originalTimerColor = (Color)property.GetValue(value5);
								Color val5 = GRACEPlusPlugin.ParseColor(GRACEPlusPlugin.TagCounterColor.Value);
								property.SetValue(value5, val5);
							}
						}
					}
				}
				if (GRACEPlusPlugin.UseCustomCountdownColor.Value && (Object)(object)TimerUI.Instance != (Object)null)
				{
					FieldInfo field6 = typeof(TimerUI).GetField("_countdownLabel", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field6 != null)
					{
						object value6 = field6.GetValue(TimerUI.Instance);
						if (value6 != null)
						{
							PropertyInfo property2 = value6.GetType().GetProperty("color");
							if (property2 != null)
							{
								_originalCountdownColor = (Color)property2.GetValue(value6);
								Color val6 = GRACEPlusPlugin.ParseColor(GRACEPlusPlugin.CountdownColor.Value);
								property2.SetValue(value6, val6);
							}
						}
					}
				}
				TimerUIHidePatch.StoreColors(_originalTimerColor, _originalCountdownColor);
			}
			catch (Exception ex)
			{
				GRACEPlusPlugin.Logger.LogError((object)("Error hiding UI elements: " + ex.Message));
			}
		}

		public static void RestoreUIElements()
		{
			if (!_uiHidden)
			{
				return;
			}
			try
			{
				if (GRACEPlusPlugin.HideChatDuringRace.Value && (Object)(object)ChatUI.Instance != (Object)null)
				{
					FieldInfo field = typeof(ChatUI).GetField("_chatWindow", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field != null)
					{
						object? value = field.GetValue(ChatUI.Instance);
						GameObject val = (GameObject)((value is GameObject) ? value : null);
						if ((Object)(object)val != (Object)null)
						{
							GameObject gameObject = ((Component)val.transform.parent).gameObject;
							if ((Object)(object)gameObject != (Object)null)
							{
								gameObject.SetActive(_originalChatVisible);
								FieldInfo field2 = typeof(ChatUI).GetField("_messagesHidden", BindingFlags.Instance | BindingFlags.NonPublic);
								if (field2 != null)
								{
									field2.SetValue(ChatUI.Instance, false);
								}
								FieldInfo field3 = typeof(ChatUI).GetField("_messageHideTimer", BindingFlags.Instance | BindingFlags.NonPublic);
								if (field3 != null)
								{
									field3.SetValue(ChatUI.Instance, 0f);
								}
								FieldInfo field4 = typeof(ChatUI).GetField("_scrollRect", BindingFlags.Instance | BindingFlags.NonPublic);
								if (field4 != null)
								{
									object value2 = field4.GetValue(ChatUI.Instance);
									if (value2 != null)
									{
										object obj = ((value2 is Component) ? value2 : null);
										GameObject val2 = ((obj != null) ? ((Component)obj).gameObject : null);
										if ((Object)(object)val2 != (Object)null)
										{
											val2.SetActive(true);
										}
									}
								}
							}
						}
					}
				}
				if (GRACEPlusPlugin.HideLobbyUIDuringRace.Value && (Object)(object)LobbyUI.Instance != (Object)null)
				{
					FieldInfo field5 = typeof(LobbyUI).GetField("_canvas", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field5 != null)
					{
						object? value3 = field5.GetValue(LobbyUI.Instance);
						GameObject val3 = (GameObject)((value3 is GameObject) ? value3 : null);
						if ((Object)(object)val3 != (Object)null)
						{
							val3.SetActive(_originalLobbyVisible);
						}
					}
				}
				if (GRACEPlusPlugin.HideMinimapDuringRace.Value && (Object)(object)MPMapController.Instance != (Object)null)
				{
					FieldInfo field6 = typeof(MPMapController).GetField("_mapUI", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field6 != null)
					{
						object value4 = field6.GetValue(MPMapController.Instance);
						if (value4 != null)
						{
							object obj2 = ((value4 is Component) ? value4 : null);
							GameObject val4 = ((obj2 != null) ? ((Component)obj2).gameObject : null);
							if ((Object)(object)val4 != (Object)null)
							{
								val4.SetActive(_originalMinimapVisible);
							}
						}
					}
				}
				if (GRACEPlusPlugin.HideTagCounterDuringRace.Value && (Object)(object)TimerUI.Instance != (Object)null)
				{
					FieldInfo field7 = typeof(TimerUI).GetField("_canvas", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field7 != null)
					{
						object? value5 = field7.GetValue(TimerUI.Instance);
						GameObject val5 = (GameObject)((value5 is GameObject) ? value5 : null);
						if ((Object)(object)val5 != (Object)null)
						{
							val5.SetActive(_originalTimerVisible);
						}
					}
				}
				_uiHidden = false;
			}
			catch (Exception ex)
			{
				GRACEPlusPlugin.Logger.LogError((object)("Error restoring UI elements: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(GraffitiRace), "OnEnd")]
	internal class UIRestoringOnEndPatch
	{
		private static void Postfix(GraffitiRace __instance, bool cancelled)
		{
			UIHidingOnStartPatch.RestoreUIElements();
		}
	}
	[HarmonyPatch(typeof(ChatUI), "ShowMessages")]
	internal class ChatUIShowMessagesPatch
	{
		private static bool Prefix()
		{
			if (GRACEPlusPlugin.HideChatDuringRace.Value && UIHidingOnStartPatch.IsUIHidden())
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(LobbyUI), "Activate")]
	internal class LobbyUIActivatePatch
	{
		private static bool Prefix()
		{
			if (GRACEPlusPlugin.HideLobbyUIDuringRace.Value && UIHidingOnStartPatch.IsUIHidden())
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(TimerUI), "Hide")]
	internal class TimerUIHidePatch
	{
		private static Color _originalTimerColor = Color.white;

		private static Color _originalCountdownColor = Color.white;

		private static bool _colorsStored = false;

		public static void StoreColors(Color timerColor, Color countdownColor)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			_originalTimerColor = timerColor;
			_originalCountdownColor = countdownColor;
			_colorsStored = true;
		}

		private static void Prefix(TimerUI __instance)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			if (!_colorsStored)
			{
				return;
			}
			try
			{
				if (GRACEPlusPlugin.UseCustomTagCounterColor.Value)
				{
					FieldInfo field = typeof(TimerUI).GetField("_label", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field != null)
					{
						object value = field.GetValue(__instance);
						if (value != null)
						{
							PropertyInfo property = value.GetType().GetProperty("color");
							if (property != null)
							{
								property.SetValue(value, _originalTimerColor);
							}
						}
					}
				}
				if (GRACEPlusPlugin.UseCustomCountdownColor.Value)
				{
					FieldInfo field2 = typeof(TimerUI).GetField("_countdownLabel", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field2 != null)
					{
						object value2 = field2.GetValue(__instance);
						if (value2 != null)
						{
							PropertyInfo property2 = value2.GetType().GetProperty("color");
							if (property2 != null)
							{
								property2.SetValue(value2, _originalCountdownColor);
							}
						}
					}
				}
				_colorsStored = false;
			}
			catch (Exception ex)
			{
				GRACEPlusPlugin.Logger.LogError((object)("Error restoring colors before hiding: " + ex.Message));
			}
		}
	}
}