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