Decompiled source of LocalGRACE v1.1.3
LocalGRACE.dll
Decompiled 21 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; 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 System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Configuration; using CommonAPI.Phone; using HarmonyLib; using Reptile; using Reptile.Phone; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; 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("LocalGRACE")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("LocalGRACE")] [assembly: AssemblyTitle("LocalGRACE")] [assembly: AssemblyVersion("1.0.0.0")] namespace LocalGRACE { public static class CompressionUtil { private static readonly MD5 Hasher = MD5.Create(); public static int HashString(string s) { return BitConverter.ToInt32(Hasher.ComputeHash(Encoding.UTF8.GetBytes(s)), 0); } } public static class GameAPI { private const BindingFlags Any = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; private static MethodInfo _cachedSceneNameToStageMethod; public static object GetSceneObjectsRegister(WorldHandler worldHandler) { if ((Object)(object)worldHandler == (Object)null) { return null; } return GetFieldOrProp(worldHandler, "sceneObjectsRegister", "SceneObjectsRegister"); } public static IList GetStageChunks(WorldHandler worldHandler) { object sceneObjectsRegister = GetSceneObjectsRegister(worldHandler); if (sceneObjectsRegister == null) { return null; } return GetFieldOrProp(sceneObjectsRegister, "stageChunks", "StageChunks") as IList; } public static List<GraffitiSpot> GetGrafSpots(WorldHandler worldHandler) { if ((Object)(object)worldHandler == (Object)null) { return null; } object sceneObjectsRegister = GetSceneObjectsRegister(worldHandler); if (sceneObjectsRegister == null) { return null; } object obj = GetFieldOrProp(sceneObjectsRegister, "grafSpots", "GrafSpots") ?? GetFieldOrProp(sceneObjectsRegister, "graffitiSpots", "GraffitiSpots") ?? GetGrafSpotsFromRegisterFallback(sceneObjectsRegister); if (obj == null) { return null; } if (obj is List<GraffitiSpot> result) { return result; } if (obj is Array array) { List<GraffitiSpot> list = new List<GraffitiSpot>(); { foreach (object item in array) { GraffitiSpot val = (GraffitiSpot)((item is GraffitiSpot) ? item : null); if (val != null) { list.Add(val); } } return list; } } if (obj is IList list2) { List<GraffitiSpot> list3 = new List<GraffitiSpot>(); for (int i = 0; i < list2.Count; i++) { object? obj2 = list2[i]; GraffitiSpot val2 = (GraffitiSpot)((obj2 is GraffitiSpot) ? obj2 : null); if (val2 != null) { list3.Add(val2); } } return list3; } if (obj is IEnumerable enumerable) { List<GraffitiSpot> list4 = new List<GraffitiSpot>(); { foreach (object item2 in enumerable) { GraffitiSpot val3 = (GraffitiSpot)((item2 is GraffitiSpot) ? item2 : null); if (val3 != null) { list4.Add(val3); } } return list4; } } return null; } public static bool IsValidGraffitiSpotForRace(GraffitiSpot x) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 try { if ((Object)(object)x == (Object)null) { return false; } if (x is GraffitiSpotFinisher) { return false; } if (GetGraffitiSpotBool(x, "deactivateDuringEncounters", "DeactivateDuringEncounters", defaultVal: false)) { return false; } if ((int)GetGraffitiSpotEnum<AttachType>(x, "attachedTo", "AttachedTo", (AttachType)0) != 0) { return false; } if ((int)GetGraffitiSpotEnum<PlayerType>(x, "notAllowedToPaint", "NotAllowedToPaint", (PlayerType)(-1)) == 0) { return false; } if ((Object)(object)((Component)x).GetComponentInParent<Rigidbody>(true) != (Object)null) { return false; } if ((int)GetGraffitiSpotEnum<ObjectiveID>(x, "beTargetForObjective", "BeTargetForObjective", (ObjectiveID)(-1)) != -1) { return false; } if ((Object)(object)((Component)x).GetComponentInParent<ActiveOnChapter>(true) != (Object)null) { return false; } return true; } catch { return true; } } private static object GetGrafSpotsFromRegisterFallback(object register) { if (register == null) { return null; } Type type = register.GetType(); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; PropertyInfo[] properties = type.GetProperties(bindingAttr); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.PropertyType == typeof(List<GraffitiSpot>)) { return propertyInfo.GetValue(register); } if (propertyInfo.PropertyType.IsGenericType) { Type[] genericArguments = propertyInfo.PropertyType.GetGenericArguments(); if (genericArguments.Length == 1 && (genericArguments[0] == typeof(GraffitiSpot) || typeof(GraffitiSpot).IsAssignableFrom(genericArguments[0]))) { return propertyInfo.GetValue(register); } } } FieldInfo[] fields = type.GetFields(bindingAttr); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(List<GraffitiSpot>)) { return fieldInfo.GetValue(register); } if (fieldInfo.FieldType.IsGenericType) { Type[] genericArguments2 = fieldInfo.FieldType.GetGenericArguments(); if (genericArguments2.Length == 1 && (genericArguments2[0] == typeof(GraffitiSpot) || typeof(GraffitiSpot).IsAssignableFrom(genericArguments2[0]))) { return fieldInfo.GetValue(register); } } } return null; } private static bool GetGraffitiSpotBool(GraffitiSpot spot, string name1, string name2, bool defaultVal) { return GetFieldOrProp(spot, name1, name2, defaultVal); } private static T GetGraffitiSpotEnum<T>(GraffitiSpot spot, string name1, string name2, T defaultVal) where T : struct { object fieldOrProp = GetFieldOrProp(spot, name1, name2); if (fieldOrProp is T) { return (T)fieldOrProp; } if (fieldOrProp is int value && typeof(T).IsEnum) { try { return (T)Enum.ToObject(typeof(T), value); } catch { } } if (fieldOrProp != null && fieldOrProp.GetType().IsValueType) { try { return (T)fieldOrProp; } catch { } } return defaultVal; } public static GraffitiSpot GetGraffitiGameSpot(GraffitiGame game) { if ((Object)(object)game == (Object)null) { return null; } return GetFieldOrProp<GraffitiSpot>(game, "gSpot", "GSpot"); } public static List<GraffitiSpot> GetPlayerGraffitiSpotsAvailable(Player player) { if ((Object)(object)player == (Object)null) { return null; } return GetFieldOrProp<List<GraffitiSpot>>(player, "graffitiSpotsAvailable", "GraffitiSpotsAvailable"); } public static bool GetPlayerUserInputEnabled(Player player) { if ((Object)(object)player == (Object)null) { return true; } return GetFieldOrProp(player, "userInputEnabled", "UserInputEnabled", defaultVal: true); } public static void SetPlayerUserInputEnabled(Player player, bool value) { if (!((Object)(object)player == (Object)null)) { SetFieldOrProp(player, "userInputEnabled", "UserInputEnabled", value); } } public static bool GetPlayerIsAI(Player player) { if ((Object)(object)player == (Object)null) { return false; } return GetFieldOrProp(player, "isAI", "IsAI", defaultVal: false); } public static bool PlayerIsBusyOrDead(Player player) { if ((Object)(object)player == (Object)null) { return true; } if (player.IsBusyWithSequence() || player.IsDead()) { return true; } object fieldOrProp = GetFieldOrProp(player, "ability", "Ability"); object fieldOrProp2 = GetFieldOrProp(player, "danceAbility", "DanceAbility"); if (fieldOrProp != null && fieldOrProp2 != null && fieldOrProp == fieldOrProp2) { return true; } return GetPlayerIsAI(player); } public static void SetPlayerGraffitiSpotsAvailableClear(Player player) { GetPlayerGraffitiSpotsAvailable(player)?.Clear(); } public static GraffitiArt GetRandomGraffitiArt(GraffitiSpot spot, Player player) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: 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_0155: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)spot == (Object)null || (Object)(object)player == (Object)null) { return null; } if ((int)spot.size == 0) { object fieldOrProp = GetFieldOrProp(spot, "GraffitiArtInfo", "graffitiArtInfo"); if (fieldOrProp == null) { return null; } MethodInfo method = fieldOrProp.GetType().GetMethod("FindByCharacter", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, new Type[1] { typeof(Characters) }, null); if (method != null && GetFieldOrProp(player, "character", "Character") is Characters val) { object? obj = method.Invoke(fieldOrProp, new object[1] { val }); return (GraffitiArt)((obj is GraffitiArt) ? obj : null); } } object fieldOrProp2 = GetFieldOrProp(spot, "GraffitiArtInfo", "graffitiArtInfo"); if (fieldOrProp2 == null) { return null; } if (!(GetFieldOrProp(fieldOrProp2, "graffitiArt", "GraffitiArt") is IEnumerable source)) { return null; } List<GraffitiArt> list = source.Cast<GraffitiArt>().ToList(); if (list.Count == 0) { return null; } GraffitiSize size = spot.size; List<GraffitiArt> list2 = new List<GraffitiArt>(); foreach (GraffitiArt item in list) { object fieldOrProp3 = GetFieldOrProp(item, "graffitiSize", "GraffitiSize"); if (fieldOrProp3 != null && (fieldOrProp3.Equals(size) || (fieldOrProp3 is GraffitiSize val2 && val2 == size))) { list2.Add(item); } } if (list2.Count == 0) { return list[Random.Range(0, list.Count)]; } return list2[Random.Range(0, list2.Count)]; } public static void GraffitiSpotPaint(GraffitiSpot spot, Crew crew, GraffitiArt art, object optional = null) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)spot == (Object)null)) { MethodInfo methodInfo = typeof(GraffitiSpot).GetMethod("Paint", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, new Type[3] { typeof(Crew), typeof(GraffitiArt), typeof(object) }, null) ?? typeof(GraffitiSpot).GetMethod("Paint", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (methodInfo != null) { methodInfo.Invoke(spot, (methodInfo.GetParameters().Length != 3) ? new object[2] { crew, art } : new object[3] { crew, art, optional }); } } } public static void GraffitiSpotClearPaint(GraffitiSpot spot) { if (!((Object)(object)spot == (Object)null)) { InvokeMethod(spot, "ClearPaint", "clearPaint"); } } public static void PlayerPlaySfxGraffitiComplete(Player player) { if ((Object)(object)player == (Object)null) { return; } object fieldOrProp = GetFieldOrProp(player, "audioManager", "AudioManager"); if (fieldOrProp == null) { return; } MethodInfo methodInfo = fieldOrProp.GetType().GetMethod("PlaySfxGameplay", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, new Type[3] { typeof(SfxCollectionID), typeof(AudioClipID), typeof(float) }, null) ?? fieldOrProp.GetType().GetMethod("PlaySfxGameplay", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (methodInfo != null) { if (methodInfo.GetParameters().Length == 3) { methodInfo.Invoke(fieldOrProp, new object[3] { (object)(SfxCollectionID)13, (object)(AudioClipID)559, 0f }); } else { methodInfo.Invoke(fieldOrProp, new object[2] { (object)(SfxCollectionID)13, (object)(AudioClipID)559 }); } } } public static void PlayerGrafSpotVisualizationStop(Player player) { if (!((Object)(object)player == (Object)null)) { InvokeMethod(player, "GrafSpotVisualizationStop", "grafSpotVisualizationStop"); } } public static void PlayerStoryObjectVisualizationStop(Player player) { if (!((Object)(object)player == (Object)null)) { InvokeMethod(player, "StoryObjectVisualizationStop", "storyObjectVisualizationStop"); } } public static void SetPlayerGraffitiContextAvailable(Player player, int value) { if (!((Object)(object)player == (Object)null)) { SetFieldOrProp(player, "graffitiContextAvailable", "GraffitiContextAvailable", value); } } public static PinType GetMapPinType(MapPin pin) { //IL_0037: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)pin == (Object)null) { return (PinType)(-1); } object fieldOrProp = GetFieldOrProp(pin, "m_pinType", "PinType"); if (fieldOrProp == null) { fieldOrProp = GetFieldOrProp(pin, "pinType", null); } if (fieldOrProp is PinType) { return (PinType)fieldOrProp; } if (fieldOrProp == null || !Enum.IsDefined(typeof(PinType), fieldOrProp)) { return (PinType)(-1); } return (PinType)fieldOrProp; } public static void MapPinDisable(MapPin pin) { if (!((Object)(object)pin == (Object)null)) { InvokeMethod(pin, "DisableMapPinGameObject", "disableMapPinGameObject"); } } public static object GetProgressableData(AProgressable progressable) { if ((Object)(object)progressable == (Object)null) { return null; } return GetFieldOrProp(progressable, "progressableData", "ProgressableData"); } public static void SetProgressableData(AProgressable progressable, object value) { if (!((Object)(object)progressable == (Object)null)) { SetFieldOrProp(progressable, "progressableData", "ProgressableData", value); } } public static MapPin MapControllerCreatePin(Mapcontroller mapController, PinType pinType) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mapController == (Object)null) { return null; } object? obj = typeof(Mapcontroller).GetMethod("CreatePin", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, new Type[1] { typeof(PinType) }, null)?.Invoke(mapController, new object[1] { pinType }); return (MapPin)((obj is MapPin) ? obj : null); } public static ICollection<MapPin> GetMapControllerPins(Mapcontroller mapController) { if ((Object)(object)mapController == (Object)null) { return null; } return GetFieldOrProp<ICollection<MapPin>>(mapController, "m_MapPins", "MapPins"); } public static void SetMapPinValid(MapPin pin, bool value) { if (!((Object)(object)pin == (Object)null)) { SetFieldOrProp(pin, "isMapPinValid", "IsMapPinValid", value); } } public static float GetPlayerMaxBoostCharge(Player player) { if ((Object)(object)player == (Object)null) { return 0f; } return GetFieldOrProp(player, "maxBoostCharge", "MaxBoostCharge", 1f); } public static Camera GetGameplayCameraCam() { object gameplayCamera = GetGameplayCamera(); if (gameplayCamera == null) { return null; } return GetFieldOrProp<Camera>(gameplayCamera, "cam", "Cam"); } public static object GetGameplayCamera() { Type typeFromHandle = typeof(GameplayCamera); return (typeFromHandle.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public) ?? typeFromHandle.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(null); } public static object GetUIManagerGameplay(UIManager uiManager) { if ((Object)(object)uiManager == (Object)null) { return null; } return GetFieldOrProp(uiManager, "gameplay", "Gameplay"); } public static bool IsGameplayScreenActive(UIManager uiManager) { object uIManagerGameplay = GetUIManagerGameplay(uiManager); if (uIManagerGameplay == null) { return false; } object fieldOrProp = GetFieldOrProp(uIManagerGameplay, "gameplayScreen", "GameplayScreen"); object obj = ((fieldOrProp is Component) ? fieldOrProp : null); GameObject val = ((obj != null) ? ((Component)obj).gameObject : null); if ((Object)(object)val != (Object)null) { return val.activeInHierarchy; } return false; } private static T GetFieldOrProp<T>(object obj, string name1, string name2, T defaultVal = default(T)) { object fieldOrProp = GetFieldOrProp(obj, name1, name2, (object)defaultVal); if (fieldOrProp == null && default(T) == null) { return defaultVal; } if (fieldOrProp is T) { return (T)fieldOrProp; } try { return (T)Convert.ChangeType(fieldOrProp, typeof(T)); } catch { return defaultVal; } } private static object GetFieldOrProp(object obj, string name1, string name2, object defaultVal = null) { if (obj == null) { return defaultVal; } Type type2 = ((obj is Type type) ? type : obj.GetType()); BindingFlags bindingAttr = ((obj is Type) ? (BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) : (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); for (int i = 0; i < 2; i++) { string text = ((i == 0) ? name1 : name2); if (!string.IsNullOrEmpty(text)) { FieldInfo field = type2.GetField(text, bindingAttr); if (field != null) { return field.GetValue((obj is Type) ? null : obj); } PropertyInfo property = type2.GetProperty(text, bindingAttr); if (property != null) { return property.GetValue((obj is Type) ? null : obj); } } } return defaultVal; } private static void SetFieldOrProp(object obj, string name1, string name2, object value) { if (obj == null) { return; } Type type = obj.GetType(); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; for (int i = 0; i < 2; i++) { string text = ((i == 0) ? name1 : name2); if (!string.IsNullOrEmpty(text)) { FieldInfo field = type.GetField(text, bindingAttr); if (field != null) { field.SetValue(obj, value); break; } PropertyInfo property = type.GetProperty(text, bindingAttr); if (property != null && property.CanWrite) { property.SetValue(obj, value); break; } } } } private static void InvokeMethod(object obj, string name1, string name2) { if (obj == null) { return; } Type type = obj.GetType(); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; for (int i = 0; i < 2; i++) { string text = ((i == 0) ? name1 : name2); if (!string.IsNullOrEmpty(text)) { MethodInfo method = type.GetMethod(text, bindingAttr, null, Type.EmptyTypes, null); if (method != null) { method.Invoke(obj, null); break; } } } } public static int GetCurrentStageId() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { Scene activeScene = SceneManager.GetActiveScene(); string sceneName = ((Scene)(ref activeScene)).name ?? ""; int currentStageIdFromSceneName = GetCurrentStageIdFromSceneName(); if (currentStageIdFromSceneName >= 0) { return currentStageIdFromSceneName; } return GetCurrentStageIdFromBombRushMP(sceneName); } catch { return -1; } } public static bool IsInBombRushMPLobby() { if (!LocalGRACEPlugin.HasBombRushMP) { return false; } try { Type typeFromAnyAssembly = GetTypeFromAnyAssembly("BombRushMP.Plugin.ClientController"); if (typeFromAnyAssembly == null) { return false; } PropertyInfo property = typeFromAnyAssembly.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); if (property == null) { return false; } object value = property.GetValue(null); if (value == null) { return false; } PropertyInfo property2 = typeFromAnyAssembly.GetProperty("ClientLobbyManager", BindingFlags.Instance | BindingFlags.Public); if (property2 == null) { return false; } object value2 = property2.GetValue(value); if (value2 == null) { return false; } PropertyInfo property3 = value2.GetType().GetProperty("CurrentLobby", BindingFlags.Instance | BindingFlags.Public); if (property3 == null) { return false; } return property3.GetValue(value2) != null; } catch { return false; } } private static int GetCurrentStageIdFromBombRushMP(string sceneName) { if (string.IsNullOrEmpty(sceneName)) { return -1; } try { MethodInfo methodInfo = FindSceneNameToStageMethod(); if (methodInfo == null) { return -1; } object obj = methodInfo.Invoke(null, new object[1] { sceneName }); if (obj == null) { return -1; } if (obj is Enum value) { return Convert.ToInt32(value); } if (obj is int result) { return result; } return Convert.ToInt32(obj); } catch { return -1; } } private static MethodInfo FindSceneNameToStageMethod() { if (_cachedSceneNameToStageMethod != null) { return _cachedSceneNameToStageMethod; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type[] exportedTypes = assembly.GetExportedTypes(); foreach (Type type in exportedTypes) { try { MethodInfo method = type.GetMethod("SceneNameToStage", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); if (method != null && method.ReturnType != typeof(void)) { _cachedSceneNameToStageMethod = method; return method; } } catch { } } } catch { } } return null; } private static Type GetTypeFromAnyAssembly(string typeName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type = assembly.GetType(typeName); if (type != null) { return type; } } catch { } } return null; } private static int GetCurrentStageIdFromSceneName() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); string text = ((Scene)(ref activeScene)).name ?? ""; if (string.IsNullOrEmpty(text)) { return -1; } Type type = typeof(WorldHandler).Assembly.GetType("Reptile.Stage") ?? typeof(WorldHandler).Assembly.GetType("Stage"); if (type == null || !type.IsEnum) { return -1; } string text2 = text.ToLowerInvariant(); string[] names = Enum.GetNames(type); Array values = Enum.GetValues(type); int result = -1; int num = 0; for (int i = 0; i < names.Length; i++) { string text3 = names[i].ToLowerInvariant(); if (text3.Length != 0 && (text2.Equals(text3, StringComparison.OrdinalIgnoreCase) || text2.Contains(text3)) && text3.Length > num) { num = text3.Length; result = (int)values.GetValue(i); } } return result; } } public static class GraceStats { private static string _recordsFilePath; private static string _mapStatsFolder; private static Dictionary<int, double> _bestTimes = new Dictionary<int, double>(); public static void Initialize() { string text = Path.Combine(Paths.BepInExRootPath, "GRACEPlus"); Directory.CreateDirectory(text); _recordsFilePath = Path.Combine(text, "grace_records.txt"); _mapStatsFolder = Path.Combine(text, "Map Stats"); Directory.CreateDirectory(_mapStatsFolder); LoadRecords(); } private static void LoadRecords() { if (!File.Exists(_recordsFilePath)) { return; } try { 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; } } } } catch { } } private static void SaveRecords() { try { List<string> list = new List<string> { "# GRACEPlus Best Times (Solo Mode)", "# 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); } catch { } } public static bool CheckAndUpdateBestTime(int stageId, double timeInSeconds, out double? previousBest) { previousBest = null; if (stageId < 0) { return false; } bool flag = false; 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 void SaveMapStats(int stageId, double timeInSeconds, bool won) { if (stageId < 0) { return; } try { 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 = string.Format("{0},{1:F1},{2},{3},{4}", text, timeInSeconds, text2, "SOLO", "NORMAL"); if (!File.Exists(path)) { List<string> contents = new List<string> { "# GRACEPlus Map Statistics", $"# Stage: {stageId}", "# Format: Timestamp,Time,Result,GameType,ModeType", "# Result: WIN or LOSS", "# GameType: MULTIPLAYER or SOLO", "# ModeType: TEAM or NORMAL", "" }; File.WriteAllLines(path, contents); } File.AppendAllText(path, text3 + Environment.NewLine); } catch { } } public static double? GetBestTime(int stageId) { if (stageId < 0) { return null; } LoadRecords(); if (!_bestTimes.ContainsKey(stageId)) { return null; } return _bestTimes[stageId]; } public static double? GetAverageTime(int stageId) { if (stageId < 0) { return null; } string path = Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt"); if (!File.Exists(path)) { return null; } try { 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("#")) { continue; } 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") { if (array3.Length >= 5 && array3[4] == "NORMAL") { list.Add(result); } else if (array3.Length < 5) { list.Add(result); } } } return (list.Count > 0) ? new double?(list.Average()) : null; } catch { return null; } } public static bool ClearBestTime(int stageId) { if (stageId < 0) { return false; } if (!_bestTimes.ContainsKey(stageId)) { return false; } _bestTimes.Remove(stageId); SaveRecords(); return true; } public static bool ClearMapStats(int stageId) { if (stageId < 0) { return false; } string path = Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt"); if (!File.Exists(path)) { return false; } try { File.Delete(path); return true; } catch { return false; } } public static int GetGamesPlayed(int stageId) { if (stageId < 0) { return 0; } string path = Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt"); if (!File.Exists(path)) { return 0; } try { string[] array = File.ReadAllLines(path); int num = 0; string[] array2 = array; foreach (string text in array2) { if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("#") && text.Split(new char[1] { ',' }).Length >= 3) { num++; } } return num; } catch { return 0; } } public static int GetSoloGamesCount(int stageId) { if (stageId < 0) { return 0; } string path = Path.Combine(_mapStatsFolder, $"Stage_{stageId}.txt"); if (!File.Exists(path)) { return 0; } try { 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 >= 4 && array3[3] == "SOLO") { num++; } } } return num; } catch { return 0; } } } public enum GraffitiSpotIndicatorStyle { Normal, PinkCan, RainbowCan, RedCan, WhiteCan, PurpleCan, OrangeCan, GreenCan, BlackCan } public enum GraffitiOutlineColor { Green, Red, Yellow, Blue, Pink, Purple, Orange, White, Black } [BepInPlugin("com.localgrace", "LocalGRACE", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class LocalGRACEPlugin : BaseUnityPlugin { private static Harmony _harmony; internal static LocalGRACEPlugin Instance; internal static bool HasBombRushMP; private static StandaloneGraffitiRace _race; public static ConfigEntry<int> DefaultSpotCount; public static ConfigEntry<int> CountdownSeconds; public static ConfigEntry<bool> QuickGraffiti; public static ConfigEntry<bool> AutoGraffiti; public static ConfigEntry<GraffitiSpotIndicatorStyle> GraffitiSpotIndicator; public static ConfigEntry<bool> UseCustomGraffitiIndicator; public static ConfigEntry<GraffitiOutlineColor> GraffitiOutlineColorPreset; public static ConfigEntry<bool> UseGraffitiOutlineColorHexCode; public static ConfigEntry<string> GraffitiOutlineColorHexCode; public static ConfigEntry<bool> AutoStart; public static ConfigEntry<int> AutoStartDelay; public static ConfigEntry<bool> SaveToStats; public static ConfigEntry<bool> ShowUICountdownTimer; public static ConfigEntry<bool> ShowUIRaceTimeTracker; public static ConfigEntry<bool> ShowUITagCounter; public static ConfigEntry<bool> ShowUIPB; public static ConfigEntry<bool> ShowUIAVG; public static ConfigEntry<string> UICountdownTimerColorHex; public static ConfigEntry<string> UIRaceTimeTrackerColorHex; public static ConfigEntry<string> UITagCounterColorHex; public static ConfigEntry<string> UIPBColorHex; public static ConfigEntry<string> UIAVGColorHex; private float _autoStartAtTime; private Coroutine _autoStartCoroutine; public static string ModFolder { get; private set; } public static StandaloneGraffitiRace Race => _race ?? (_race = new StandaloneGraffitiRace()); public static string GetCustomGraffitiSignPath() { if (UseCustomGraffitiIndicator == null || !UseCustomGraffitiIndicator.Value) { return null; } try { string text = Path.Combine(Paths.BepInExRootPath, "GRACEPlus"); string text2 = Path.Combine(text, "Textures"); string path = Path.Combine(text2, "GraffitiSign"); Directory.CreateDirectory(text); Directory.CreateDirectory(text2); Directory.CreateDirectory(path); string[] files = Directory.GetFiles(path, "*.png", SearchOption.TopDirectoryOnly); return (files.Length != 0) ? files[0] : null; } catch { return null; } } public static string GetBackendTexturePath(string filename) { if (!string.IsNullOrEmpty(ModFolder)) { return Path.Combine(ModFolder, "backendtextures", filename); } return null; } public static string GetAppIconPath() { if (string.IsNullOrEmpty(ModFolder)) { return null; } try { string path = Path.Combine(ModFolder, "backendtextures", "AppIcon"); if (!Directory.Exists(path)) { return null; } string[] files = Directory.GetFiles(path, "*.png", SearchOption.TopDirectoryOnly); return (files.Length != 0) ? files[0] : null; } catch { return null; } } public static string GetGraffitiIndicatorFilename(GraffitiSpotIndicatorStyle style) { return style switch { GraffitiSpotIndicatorStyle.PinkCan => "PinkCan_GraffitiSign.png", GraffitiSpotIndicatorStyle.RainbowCan => "RainbowCan_GraffitiSign.png", GraffitiSpotIndicatorStyle.RedCan => "RedCan_GraffitiSign.png", GraffitiSpotIndicatorStyle.WhiteCan => "WhiteCan_GraffitiSign.png", GraffitiSpotIndicatorStyle.PurpleCan => "PurpleCan_GraffitiSign.png", GraffitiSpotIndicatorStyle.OrangeCan => "OrangeCan_GraffitiSign.png", GraffitiSpotIndicatorStyle.GreenCan => "GreenCan_GraffitiSign.png", GraffitiSpotIndicatorStyle.BlackCan => "BlackCan_GraffitiSign.png", _ => "GraffitiSign.png", }; } public static Color GetOutlineColor(GraffitiOutlineColor color) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) return (Color)(color switch { GraffitiOutlineColor.Red => new Color(1f, 0.2f, 0.2f), GraffitiOutlineColor.Yellow => new Color(1f, 0.9f, 0.2f), GraffitiOutlineColor.Blue => new Color(0.2f, 0.5f, 1f), GraffitiOutlineColor.Pink => new Color(1f, 0.4f, 0.6f), GraffitiOutlineColor.Purple => new Color(0.6f, 0.2f, 1f), GraffitiOutlineColor.Orange => new Color(1f, 0.5f, 0.1f), GraffitiOutlineColor.White => new Color(1f, 1f, 1f), GraffitiOutlineColor.Black => new Color(0.1f, 0.1f, 0.1f), _ => new Color(0.2f, 1f, 0.3f), }); } public static Color GetEffectiveOutlineColor() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (UseGraffitiOutlineColorHexCode != null && UseGraffitiOutlineColorHexCode.Value && GraffitiOutlineColorHexCode != null && !string.IsNullOrWhiteSpace(GraffitiOutlineColorHexCode.Value)) { string text = GraffitiOutlineColorHexCode.Value.Trim(); if (!text.StartsWith("#")) { text = "#" + text; } Color result = default(Color); if (ColorUtility.TryParseHtmlString(text, ref result)) { return result; } } return GetOutlineColor((GraffitiOutlineColorPreset != null) ? GraffitiOutlineColorPreset.Value : GraffitiOutlineColor.Green); } public static bool IsOutlineColorDefault() { if (UseGraffitiOutlineColorHexCode != null && UseGraffitiOutlineColorHexCode.Value) { return false; } if (GraffitiOutlineColorPreset != null) { return GraffitiOutlineColorPreset.Value == GraffitiOutlineColor.Yellow; } return true; } public static Color GetUIColorFromHex(ConfigEntry<string> entry, Color defaultColor) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (entry == null || string.IsNullOrWhiteSpace(entry.Value)) { return defaultColor; } string text = entry.Value.Trim(); if (!text.StartsWith("#")) { text = "#" + text; } Color result = default(Color); if (ColorUtility.TryParseHtmlString(text, ref result)) { return result; } return defaultColor; } private void Awake() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Expected O, but got Unknown Instance = this; ModFolder = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); try { HasBombRushMP = AppDomain.CurrentDomain.GetAssemblies().Any((Assembly a) => a.GetName().Name?.StartsWith("BombRushMP", StringComparison.OrdinalIgnoreCase) ?? false); } catch { HasBombRushMP = false; } DefaultSpotCount = ((BaseUnityPlugin)this).Config.Bind<int>("Race", "DefaultSpotCount", 10, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 70), Array.Empty<object>())); CountdownSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Race", "CountdownSeconds", 3, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>())); QuickGraffiti = ((BaseUnityPlugin)this).Config.Bind<bool>("Race", "QuickGraffiti", true, ""); AutoGraffiti = ((BaseUnityPlugin)this).Config.Bind<bool>("Race", "AutoGraffiti", false, ""); GraffitiSpotIndicator = ((BaseUnityPlugin)this).Config.Bind<GraffitiSpotIndicatorStyle>("Indicators", "GraffitiSpotIndicator", GraffitiSpotIndicatorStyle.Normal, ""); UseCustomGraffitiIndicator = ((BaseUnityPlugin)this).Config.Bind<bool>("Indicators", "UseCustomGraffitiIndicator", false, ""); GraffitiOutlineColorPreset = ((BaseUnityPlugin)this).Config.Bind<GraffitiOutlineColor>("Indicators", "GraffitiOutlineColor", GraffitiOutlineColor.Green, ""); UseGraffitiOutlineColorHexCode = ((BaseUnityPlugin)this).Config.Bind<bool>("Indicators", "Use Graffiti Outline Color Hex Code", false, ""); GraffitiOutlineColorHexCode = ((BaseUnityPlugin)this).Config.Bind<string>("Indicators", "Graffiti Outline Color Hex Code", "#00FF4D", ""); AutoStart = ((BaseUnityPlugin)this).Config.Bind<bool>("Race", "AutoStart", false, ""); AutoStartDelay = ((BaseUnityPlugin)this).Config.Bind<int>("Race", "AutoStartDelay", 3, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>())); SaveToStats = ((BaseUnityPlugin)this).Config.Bind<bool>("Race", "SaveToStats", true, ""); ShowUICountdownTimer = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowUICountdownTimer", true, ""); ShowUIRaceTimeTracker = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowUIRaceTimeTracker", true, ""); ShowUITagCounter = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowUITagCounter", true, ""); ShowUIPB = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowUIPB", true, ""); ShowUIAVG = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowUIAVG", true, ""); UICountdownTimerColorHex = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "UICountdownTimerColorHex", "#FFFF00", ""); UIRaceTimeTrackerColorHex = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "UIRaceTimeTrackerColorHex", "#D9D9D9", ""); UITagCounterColorHex = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "UITagCounterColorHex", "#FFFFFF", ""); UIPBColorHex = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "UIPBColorHex", "#00FF00", ""); UIAVGColorHex = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "UIAVGColorHex", "#FFFF00", ""); GraceStats.Initialize(); _harmony = new Harmony("com.localgrace"); _harmony.PatchAll(); AppLocalGRACE.Initialize(); } private void Update() { if (Race != null && Race.InGame) { Race.Update(); } } private IEnumerator AutoStartAfterDelay(float delay) { yield return (object)new WaitForSeconds(delay); _autoStartCoroutine = null; if ((Object)(object)Instance == (Object)null || Race == null || _autoStartAtTime == 0f) { yield break; } _autoStartAtTime = 0f; if (Race.InGame) { yield break; } try { int lastCountdownSecondsForAutoStart = AppLocalGRACE.LastCountdownSecondsForAutoStart; int lastSpotAmountForAutoStart = AppLocalGRACE.LastSpotAmountForAutoStart; Race.SetCountdown(lastCountdownSecondsForAutoStart); Race.StartRace(lastSpotAmountForAutoStart); } catch { } } internal static void OnRaceEnded(bool cancelled) { if ((Object)(object)Instance == (Object)null) { return; } if (cancelled) { if (Instance._autoStartCoroutine != null) { ((MonoBehaviour)Instance).StopCoroutine(Instance._autoStartCoroutine); Instance._autoStartCoroutine = null; } Instance._autoStartAtTime = 0f; if (AutoStart != null) { AutoStart.Value = false; } } else if (AutoStart.Value) { Instance._autoStartAtTime = Time.time + (float)AutoStartDelay.Value; if (Instance._autoStartCoroutine != null) { ((MonoBehaviour)Instance).StopCoroutine(Instance._autoStartCoroutine); } Instance._autoStartCoroutine = ((MonoBehaviour)Instance).StartCoroutine(Instance.AutoStartAfterDelay(AutoStartDelay.Value)); } } internal static void CancelAutoStart() { if (!((Object)(object)Instance == (Object)null)) { if (Instance._autoStartCoroutine != null) { ((MonoBehaviour)Instance).StopCoroutine(Instance._autoStartCoroutine); Instance._autoStartCoroutine = null; } Instance._autoStartAtTime = 0f; } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public static class PluginInfo { public const string PLUGIN_GUID = "com.localgrace"; public const string PLUGIN_NAME = "LocalGRACE"; public const string PLUGIN_VERSION = "1.0.0"; } public class AppLocalGRACE : CustomApp { private SimplePhoneButton _startOrEndButton; private SimplePhoneButton _spotAmountButton; private SimplePhoneButton _countdownButton; private SimplePhoneButton _autoStartButton; private SimplePhoneButton _autoStartDelayButton; private SimplePhoneButton _graffitiSignButton; private SimplePhoneButton _graffitiOutlineColorButton; private bool _showingExtraSettings; private bool _showingStats; private int _spotAmount = 10; private int _countdownSeconds = 3; private int _maxSpotsOnMap = 1; public static int LastSpotAmountForAutoStart { get; private set; } public static int LastCountdownSecondsForAutoStart { get; private set; } public static void Initialize() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) Sprite val = null; string appIconPath = LocalGRACEPlugin.GetAppIconPath(); if (!string.IsNullOrEmpty(appIconPath) && File.Exists(appIconPath)) { try { byte[] array = File.ReadAllBytes(appIconPath); Texture2D val2 = new Texture2D(2, 2); if (ImageConversion.LoadImage(val2, array)) { ((Texture)val2).wrapMode = (TextureWrapMode)1; ((Texture)val2).filterMode = (FilterMode)1; val2.Apply(); val = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f)); } } catch { } } if ((Object)(object)val != (Object)null) { PhoneAPI.RegisterApp<AppLocalGRACE>("GRACE", val); } else { PhoneAPI.RegisterApp<AppLocalGRACE>("GRACE", (Sprite)null); } RefreshAutoStartValuesFromConfig(); } public static void RefreshAutoStartValuesFromConfig() { if (LocalGRACEPlugin.DefaultSpotCount != null) { LastSpotAmountForAutoStart = LocalGRACEPlugin.DefaultSpotCount.Value; } if (LocalGRACEPlugin.CountdownSeconds != null) { LastCountdownSecondsForAutoStart = LocalGRACEPlugin.CountdownSeconds.Value; } } public override void OnAppInit() { ((CustomApp)this).OnAppInit(); ((CustomApp)this).CreateIconlessTitleBar("Local GRACE", 80f); base.ScrollView = PhoneScrollView.Create((CustomApp)(object)this, 275f, 1600f); PopulateButtons(); } public override void OnAppEnable() { ((App)this).OnAppEnable(); _showingExtraSettings = false; _showingStats = false; RefreshMaxSpots(); ClampSpotAmountToMax(); PopulateButtons(); } public override void OnAppUpdate() { ((App)this).OnAppUpdate(); } private void RefreshMaxSpots() { StandaloneGraffitiRace race = LocalGRACEPlugin.Race; _maxSpotsOnMap = ((race == null) ? 1 : Mathf.Max(1, race.GetValidSpotCount())); } private void ClampSpotAmountToMax() { if (_spotAmount < 1 || _spotAmount > _maxSpotsOnMap) { _spotAmount = Mathf.Clamp(_spotAmount, 1, _maxSpotsOnMap); } } private void SetDefaultSpotAmount() { RefreshMaxSpots(); _spotAmount = ((_maxSpotsOnMap < 10) ? _maxSpotsOnMap : 10); } private void PopulateButtons() { base.ScrollView.RemoveAllButtons(); _showingExtraSettings = false; _showingStats = false; StandaloneGraffitiRace race = LocalGRACEPlugin.Race; RefreshMaxSpots(); if (_spotAmount < 1 || _spotAmount > _maxSpotsOnMap) { SetDefaultSpotAmount(); } _startOrEndButton = PhoneUIUtility.CreateSimpleButton(StartOrEndButtonLabel()); SimplePhoneButton startOrEndButton = _startOrEndButton; ((PhoneButton)startOrEndButton).OnConfirm = (Action)Delegate.Combine(((PhoneButton)startOrEndButton).OnConfirm, (Action)delegate { if (race.InGame) { race.EndRace(); if ((Object)(object)_startOrEndButton?.Label != (Object)null) { ((TMP_Text)_startOrEndButton.Label).text = StartOrEndButtonLabel(); } return; } try { LocalGRACEPlugin.CancelAutoStart(); LastSpotAmountForAutoStart = _spotAmount; LastCountdownSecondsForAutoStart = _countdownSeconds; race.SetCountdown(_countdownSeconds); race.StartRace(_spotAmount); ((App)this).MyPhone.TurnOff(true); } catch { } }); base.ScrollView.AddButton((PhoneButton)(object)_startOrEndButton); SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton("Stats"); ((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, (Action)delegate { ShowStatsView(); }); base.ScrollView.AddButton((PhoneButton)(object)val); SimplePhoneButton val2 = PhoneUIUtility.CreateSimpleButton("Extra Settings"); ((PhoneButton)val2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val2).OnConfirm, (Action)delegate { ShowExtraSettingsView(); }); base.ScrollView.AddButton((PhoneButton)(object)val2); _spotAmountButton = PhoneUIUtility.CreateSimpleButton(SpotAmountLabel()); SimplePhoneButton spotAmountButton = _spotAmountButton; ((PhoneButton)spotAmountButton).OnConfirm = (Action)Delegate.Combine(((PhoneButton)spotAmountButton).OnConfirm, (Action)delegate { RefreshMaxSpots(); _spotAmount++; if (_spotAmount > _maxSpotsOnMap) { _spotAmount = 1; } LastSpotAmountForAutoStart = _spotAmount; if ((Object)(object)_spotAmountButton?.Label != (Object)null) { ((TMP_Text)_spotAmountButton.Label).text = SpotAmountLabel(); } }); base.ScrollView.AddButton((PhoneButton)(object)_spotAmountButton); _countdownButton = PhoneUIUtility.CreateSimpleButton(CountdownLabel()); SimplePhoneButton countdownButton = _countdownButton; ((PhoneButton)countdownButton).OnConfirm = (Action)Delegate.Combine(((PhoneButton)countdownButton).OnConfirm, (Action)delegate { _countdownSeconds++; if (_countdownSeconds > 10) { _countdownSeconds = 1; } LastCountdownSecondsForAutoStart = _countdownSeconds; race.SetCountdown(_countdownSeconds); if ((Object)(object)_countdownButton?.Label != (Object)null) { ((TMP_Text)_countdownButton.Label).text = CountdownLabel(); } }); base.ScrollView.AddButton((PhoneButton)(object)_countdownButton); _autoStartButton = PhoneUIUtility.CreateSimpleButton(AutoStartLabel()); SimplePhoneButton autoStartButton = _autoStartButton; ((PhoneButton)autoStartButton).OnConfirm = (Action)Delegate.Combine(((PhoneButton)autoStartButton).OnConfirm, (Action)delegate { LocalGRACEPlugin.AutoStart.Value = !LocalGRACEPlugin.AutoStart.Value; if ((Object)(object)_autoStartButton?.Label != (Object)null) { ((TMP_Text)_autoStartButton.Label).text = AutoStartLabel(); } }); base.ScrollView.AddButton((PhoneButton)(object)_autoStartButton); _autoStartDelayButton = PhoneUIUtility.CreateSimpleButton(AutoStartDelayLabel()); SimplePhoneButton autoStartDelayButton = _autoStartDelayButton; ((PhoneButton)autoStartDelayButton).OnConfirm = (Action)Delegate.Combine(((PhoneButton)autoStartDelayButton).OnConfirm, (Action)delegate { int value = LocalGRACEPlugin.AutoStartDelay.Value; value++; if (value > 10) { value = 1; } LocalGRACEPlugin.AutoStartDelay.Value = value; if ((Object)(object)_autoStartDelayButton?.Label != (Object)null) { ((TMP_Text)_autoStartDelayButton.Label).text = AutoStartDelayLabel(); } }); base.ScrollView.AddButton((PhoneButton)(object)_autoStartDelayButton); SimplePhoneButton saveToStatsButton = PhoneUIUtility.CreateSimpleButton(SaveToStatsLabel()); SimplePhoneButton obj = saveToStatsButton; ((PhoneButton)obj).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj).OnConfirm, (Action)delegate { if (LocalGRACEPlugin.SaveToStats != null) { LocalGRACEPlugin.SaveToStats.Value = !LocalGRACEPlugin.SaveToStats.Value; if ((Object)(object)saveToStatsButton?.Label != (Object)null) { ((TMP_Text)saveToStatsButton.Label).text = SaveToStatsLabel(); } } }); base.ScrollView.AddButton((PhoneButton)(object)saveToStatsButton); } private void ShowExtraSettingsView() { _showingExtraSettings = true; base.ScrollView.RemoveAllButtons(); _graffitiSignButton = PhoneUIUtility.CreateSimpleButton(GraffitiSignLabel()); SimplePhoneButton graffitiSignButton = _graffitiSignButton; ((PhoneButton)graffitiSignButton).OnConfirm = (Action)Delegate.Combine(((PhoneButton)graffitiSignButton).OnConfirm, (Action)delegate { CycleGraffitiSpotIndicator(); if ((Object)(object)_graffitiSignButton?.Label != (Object)null) { ((TMP_Text)_graffitiSignButton.Label).text = GraffitiSignLabel(); } }); base.ScrollView.AddButton((PhoneButton)(object)_graffitiSignButton); _graffitiOutlineColorButton = PhoneUIUtility.CreateSimpleButton(GraffitiOutlineColorLabel()); SimplePhoneButton graffitiOutlineColorButton = _graffitiOutlineColorButton; ((PhoneButton)graffitiOutlineColorButton).OnConfirm = (Action)Delegate.Combine(((PhoneButton)graffitiOutlineColorButton).OnConfirm, (Action)delegate { CycleGraffitiOutlineColor(); if ((Object)(object)_graffitiOutlineColorButton?.Label != (Object)null) { ((TMP_Text)_graffitiOutlineColorButton.Label).text = GraffitiOutlineColorLabel(); } }); base.ScrollView.AddButton((PhoneButton)(object)_graffitiOutlineColorButton); SimplePhoneButton countdownTimerBtn = PhoneUIUtility.CreateSimpleButton(ShowUICountdownTimerLabel()); SimplePhoneButton obj = countdownTimerBtn; ((PhoneButton)obj).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj).OnConfirm, (Action)delegate { ToggleConfigRefreshLabel(LocalGRACEPlugin.ShowUICountdownTimer, countdownTimerBtn, ShowUICountdownTimerLabel); }); base.ScrollView.AddButton((PhoneButton)(object)countdownTimerBtn); SimplePhoneButton raceTimeTrackerBtn = PhoneUIUtility.CreateSimpleButton(ShowUIRaceTimeTrackerLabel()); SimplePhoneButton obj2 = raceTimeTrackerBtn; ((PhoneButton)obj2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj2).OnConfirm, (Action)delegate { ToggleConfigRefreshLabel(LocalGRACEPlugin.ShowUIRaceTimeTracker, raceTimeTrackerBtn, ShowUIRaceTimeTrackerLabel); }); base.ScrollView.AddButton((PhoneButton)(object)raceTimeTrackerBtn); SimplePhoneButton tagCounterBtn = PhoneUIUtility.CreateSimpleButton(ShowUITagCounterLabel()); SimplePhoneButton obj3 = tagCounterBtn; ((PhoneButton)obj3).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj3).OnConfirm, (Action)delegate { ToggleConfigRefreshLabel(LocalGRACEPlugin.ShowUITagCounter, tagCounterBtn, ShowUITagCounterLabel); }); base.ScrollView.AddButton((PhoneButton)(object)tagCounterBtn); SimplePhoneButton pbBtn = PhoneUIUtility.CreateSimpleButton(ShowUIPBLabel()); SimplePhoneButton obj4 = pbBtn; ((PhoneButton)obj4).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj4).OnConfirm, (Action)delegate { ToggleConfigRefreshLabel(LocalGRACEPlugin.ShowUIPB, pbBtn, ShowUIPBLabel); }); base.ScrollView.AddButton((PhoneButton)(object)pbBtn); SimplePhoneButton avgBtn = PhoneUIUtility.CreateSimpleButton(ShowUIAVGLabel()); SimplePhoneButton obj5 = avgBtn; ((PhoneButton)obj5).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj5).OnConfirm, (Action)delegate { ToggleConfigRefreshLabel(LocalGRACEPlugin.ShowUIAVG, avgBtn, ShowUIAVGLabel); }); base.ScrollView.AddButton((PhoneButton)(object)avgBtn); SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton("Back"); ((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, (Action)delegate { PopulateButtons(); }); base.ScrollView.AddButton((PhoneButton)(object)val); } private void ShowStatsView() { _showingStats = true; base.ScrollView.RemoveAllButtons(); int stageId = GameAPI.GetCurrentStageId(); double? bestTime = GraceStats.GetBestTime(stageId); double? averageTime = GraceStats.GetAverageTime(stageId); int soloGamesCount = GraceStats.GetSoloGamesCount(stageId); SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton(StatsBestTimeLabel(bestTime)); ((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, (Action)delegate { }); base.ScrollView.AddButton((PhoneButton)(object)val); SimplePhoneButton val2 = PhoneUIUtility.CreateSimpleButton(StatsAvgTimeLabel(averageTime)); ((PhoneButton)val2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val2).OnConfirm, (Action)delegate { }); base.ScrollView.AddButton((PhoneButton)(object)val2); SimplePhoneButton val3 = PhoneUIUtility.CreateSimpleButton(StatsSoloGamesLabel(soloGamesCount)); ((PhoneButton)val3).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val3).OnConfirm, (Action)delegate { }); base.ScrollView.AddButton((PhoneButton)(object)val3); SimplePhoneButton val4 = PhoneUIUtility.CreateSimpleButton("Clear Best Time"); ((PhoneButton)val4).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val4).OnConfirm, (Action)delegate { GraceStats.ClearBestTime(stageId); ShowStatsView(); }); base.ScrollView.AddButton((PhoneButton)(object)val4); SimplePhoneButton val5 = PhoneUIUtility.CreateSimpleButton("Clear AVG Time"); ((PhoneButton)val5).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val5).OnConfirm, (Action)delegate { GraceStats.ClearMapStats(stageId); ShowStatsView(); }); base.ScrollView.AddButton((PhoneButton)(object)val5); SimplePhoneButton val6 = PhoneUIUtility.CreateSimpleButton("Back"); ((PhoneButton)val6).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val6).OnConfirm, (Action)delegate { PopulateButtons(); }); base.ScrollView.AddButton((PhoneButton)(object)val6); } private static string StatsBestTimeLabel(double? bestTime) { return "Best Time: " + (bestTime.HasValue ? $"{bestTime.Value:F1}s" : "—"); } private static string StatsAvgTimeLabel(double? avgTime) { return "AVG Time: " + (avgTime.HasValue ? $"{avgTime.Value:F1}s" : "—"); } private static string StatsSoloGamesLabel(int soloGames) { return "Solo Games: " + soloGames; } private void CycleGraffitiSpotIndicator() { if (LocalGRACEPlugin.GraffitiSpotIndicator != null) { GraffitiSpotIndicatorStyle value = LocalGRACEPlugin.GraffitiSpotIndicator.Value switch { GraffitiSpotIndicatorStyle.Normal => GraffitiSpotIndicatorStyle.PinkCan, GraffitiSpotIndicatorStyle.PinkCan => GraffitiSpotIndicatorStyle.RainbowCan, GraffitiSpotIndicatorStyle.RainbowCan => GraffitiSpotIndicatorStyle.RedCan, GraffitiSpotIndicatorStyle.RedCan => GraffitiSpotIndicatorStyle.WhiteCan, GraffitiSpotIndicatorStyle.WhiteCan => GraffitiSpotIndicatorStyle.PurpleCan, GraffitiSpotIndicatorStyle.PurpleCan => GraffitiSpotIndicatorStyle.OrangeCan, GraffitiSpotIndicatorStyle.OrangeCan => GraffitiSpotIndicatorStyle.GreenCan, GraffitiSpotIndicatorStyle.GreenCan => GraffitiSpotIndicatorStyle.BlackCan, GraffitiSpotIndicatorStyle.BlackCan => GraffitiSpotIndicatorStyle.Normal, _ => GraffitiSpotIndicatorStyle.Normal, }; LocalGRACEPlugin.GraffitiSpotIndicator.Value = value; } } private static string GraffitiSignLabel() { GraffitiSpotIndicatorStyle style = ((LocalGRACEPlugin.GraffitiSpotIndicator != null) ? LocalGRACEPlugin.GraffitiSpotIndicator.Value : GraffitiSpotIndicatorStyle.Normal); return "Graffiti Sign: " + GetStyleDisplayName(style); } private static string GetStyleDisplayName(GraffitiSpotIndicatorStyle style) { return style switch { GraffitiSpotIndicatorStyle.PinkCan => "Pink Can", GraffitiSpotIndicatorStyle.RainbowCan => "Rainbow Can", GraffitiSpotIndicatorStyle.RedCan => "Red Can", GraffitiSpotIndicatorStyle.WhiteCan => "White Can", GraffitiSpotIndicatorStyle.PurpleCan => "Purple Can", GraffitiSpotIndicatorStyle.OrangeCan => "Orange Can", GraffitiSpotIndicatorStyle.GreenCan => "Green Can", GraffitiSpotIndicatorStyle.BlackCan => "Black Can", _ => "Normal", }; } private void CycleGraffitiOutlineColor() { if (LocalGRACEPlugin.GraffitiOutlineColorPreset != null) { GraffitiOutlineColor value = LocalGRACEPlugin.GraffitiOutlineColorPreset.Value switch { GraffitiOutlineColor.Green => GraffitiOutlineColor.Red, GraffitiOutlineColor.Red => GraffitiOutlineColor.Yellow, GraffitiOutlineColor.Yellow => GraffitiOutlineColor.Blue, GraffitiOutlineColor.Blue => GraffitiOutlineColor.Pink, GraffitiOutlineColor.Pink => GraffitiOutlineColor.Purple, GraffitiOutlineColor.Purple => GraffitiOutlineColor.Orange, GraffitiOutlineColor.Orange => GraffitiOutlineColor.White, GraffitiOutlineColor.White => GraffitiOutlineColor.Black, GraffitiOutlineColor.Black => GraffitiOutlineColor.Green, _ => GraffitiOutlineColor.Green, }; LocalGRACEPlugin.GraffitiOutlineColorPreset.Value = value; } } private static string GraffitiOutlineColorLabel() { return "Graffiti Outline Color: " + ((LocalGRACEPlugin.GraffitiOutlineColorPreset != null) ? LocalGRACEPlugin.GraffitiOutlineColorPreset.Value : GraffitiOutlineColor.Green).ToString().ToLowerInvariant(); } private static void ToggleConfigRefreshLabel(ConfigEntry<bool> entry, SimplePhoneButton button, Func<string> labelFunc) { if (entry != null && labelFunc != null) { entry.Value = !entry.Value; if ((Object)(object)button?.Label != (Object)null) { ((TMP_Text)button.Label).text = labelFunc(); } } } private static string ShowUICountdownTimerLabel() { bool flag = LocalGRACEPlugin.ShowUICountdownTimer != null && LocalGRACEPlugin.ShowUICountdownTimer.Value; return "Countdown Timer: " + (flag ? "On" : "Off"); } private static string ShowUIRaceTimeTrackerLabel() { bool flag = LocalGRACEPlugin.ShowUIRaceTimeTracker != null && LocalGRACEPlugin.ShowUIRaceTimeTracker.Value; return "Race Time Tracker: " + (flag ? "On" : "Off"); } private static string ShowUITagCounterLabel() { bool flag = LocalGRACEPlugin.ShowUITagCounter != null && LocalGRACEPlugin.ShowUITagCounter.Value; return "Tag Counter: " + (flag ? "On" : "Off"); } private static string ShowUIPBLabel() { bool flag = LocalGRACEPlugin.ShowUIPB != null && LocalGRACEPlugin.ShowUIPB.Value; return "PB: " + (flag ? "On" : "Off"); } private static string ShowUIAVGLabel() { bool flag = LocalGRACEPlugin.ShowUIAVG != null && LocalGRACEPlugin.ShowUIAVG.Value; return "AVG: " + (flag ? "On" : "Off"); } private static string StartOrEndButtonLabel() { StandaloneGraffitiRace race = LocalGRACEPlugin.Race; if (race != null && race.InGame) { return "End Race"; } return "Start Race"; } private string SpotAmountLabel() { return $"Spot amount: {_spotAmount}"; } private string CountdownLabel() { return $"Countdown Timer: {_countdownSeconds}s"; } private static string AutoStartLabel() { return "Auto Start: " + ((LocalGRACEPlugin.AutoStart != null && LocalGRACEPlugin.AutoStart.Value) ? "On" : "Off"); } private static string AutoStartDelayLabel() { return "Auto Start Delay: " + ((LocalGRACEPlugin.AutoStartDelay != null) ? (LocalGRACEPlugin.AutoStartDelay.Value + "s") : "—"); } private static string SaveToStatsLabel() { bool flag = LocalGRACEPlugin.SaveToStats != null && LocalGRACEPlugin.SaveToStats.Value; return "Save To Stats: " + (flag ? "On" : "Off"); } } public class StandaloneGraffitiRace { public enum State { None, Countdown, Main, Finished } private const float DistanceOffWall = 3f; private const int MinGraffiti = 5; private const int MaxGraffiti = 70; private static readonly Vector3 HideoutBlockedSpawnPosition = new Vector3(-5.05f, 9.1f, -36.35f); private const float BlockedSpawnPositionTolerance = 0.5f; private WorldHandler _worldHandler; private State _state; private float _countdownTimer; private int _score; private Dictionary<GraffitiSpot, object> _originalProgress = new Dictionary<GraffitiSpot, object>(); private HashSet<GraffitiSpot> _otherSpots = new HashSet<GraffitiSpot>(); private List<StageChunk> _offStageChunks = new List<StageChunk>(); private List<GraffitiSpot> _raceSpots = new List<GraffitiSpot>(); private Vector3 _spawnPos; private Quaternion _spawnRot; private int _countdownSeconds = 3; private float _raceElapsedTime; private TimerUI _timerUI; private UIScreenIndicators _indicators; private Dictionary<GraffitiSpot, MapPin> _mapPins = new Dictionary<GraffitiSpot, MapPin>(); private Dictionary<GraffitiSpot, List<(Renderer, Material, int, Color, Material)>> _outlineColorBackups = new Dictionary<GraffitiSpot, List<(Renderer, Material, int, Color, Material)>>(); private int _lastCountdownRemaining = -999; private int _lastDisplayedScore = -1; private string _lastFormattedRaceTime; private static readonly int ShaderPropColor = Shader.PropertyToID("_Color"); private static readonly int ShaderPropBaseColor = Shader.PropertyToID("_BaseColor"); private static readonly int ShaderPropMainTex = Shader.PropertyToID("_MainTex"); public bool InGame { get { if (_state != State.Countdown) { return _state == State.Main; } return true; } } public int Score => _score; public int TotalSpots => _raceSpots?.Count ?? 0; public State CurrentState => _state; private static bool IsBlockedHideoutSpawnSpot(GraffitiSpot spot) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)spot == (Object)null || (Object)(object)((Component)spot).transform == (Object)null) { return false; } return Vector3.Distance(((Component)spot).transform.position, HideoutBlockedSpawnPosition) <= 0.5f; } public StandaloneGraffitiRace() { _worldHandler = WorldHandler.instance; } public void SetCountdown(int seconds) { _countdownSeconds = Mathf.Clamp(seconds, 1, 10); } public void StartRace(int spotCount = -1) { //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Unknown result type (might be due to invalid IL or missing references) _worldHandler = WorldHandler.instance; if (InGame || (Object)(object)_worldHandler == (Object)null) { return; } List<GraffitiSpot> validSpots = GetValidSpots(); if (validSpots == null || validSpots.Count == 0) { return; } int num = ((spotCount > 0) ? spotCount : LocalGRACEPlugin.DefaultSpotCount.Value); num = Mathf.Clamp(num, 1, Mathf.Min(70, validSpots.Count)); if (validSpots.Count < num) { num = Mathf.Max(1, Mathf.CeilToInt((float)validSpots.Count * 0.5f)); } _raceSpots = new List<GraffitiSpot>(); List<GraffitiSpot> list = new List<GraffitiSpot>(validSpots); for (int i = 0; i < num; i++) { int index = Random.Range(0, list.Count); _raceSpots.Add(list[index]); list.RemoveAt(index); } int currentStageId = GameAPI.GetCurrentStageId(); if (currentStageId == 5 && _raceSpots.Count > 1 && IsBlockedHideoutSpawnSpot(_raceSpots[0])) { GraffitiSpot item = _raceSpots[0]; _raceSpots.RemoveAt(0); _raceSpots.Add(item); } GraffitiSpot val = _raceSpots[0]; Vector3 val2 = -((Component)val).transform.forward; _spawnPos = ((Component)val).transform.position - val2 * 3f; val2.y = 0f; val2 = ((Vector3)(ref val2)).normalized; _spawnRot = Quaternion.LookRotation(val2, Vector3.up); TurnOnAllStageChunks(); RaycastHit val5 = default(RaycastHit); foreach (GraffitiSpot raceSpot in _raceSpots) { if (currentStageId != 5 || !IsBlockedHideoutSpawnSpot(raceSpot)) { Vector3 val3 = -((Component)raceSpot).transform.forward; Vector3 val4 = ((Component)raceSpot).transform.position - val3 * 3f; if (Physics.Raycast(new Ray(val4, Vector3.down), ref val5, 1000f, int.MaxValue, (QueryTriggerInteraction)2) && Vector3.Angle(((RaycastHit)(ref val5)).normal, Vector3.up) <= 20f && ((Component)((RaycastHit)(ref val5)).collider).gameObject.layer == 0) { _spawnPos = ((RaycastHit)(ref val5)).point; val3.y = 0f; _spawnRot = Quaternion.LookRotation(((Vector3)(ref val3)).normalized, Vector3.up); break; } } } RestoreStageChunks(); _state = State.Countdown; _countdownTimer = 0f; _score = 0; _lastCountdownRemaining = -999; _lastDisplayedScore = -1; _lastFormattedRaceTime = null; _raceElapsedTime = 0f; _originalProgress.Clear(); _otherSpots.Clear(); List<GraffitiSpot> grafSpots = GameAPI.GetGrafSpots(_worldHandler); if (grafSpots != null) { foreach (GraffitiSpot item2 in grafSpots) { ((Component)item2).gameObject.SetActive(false); _otherSpots.Add(item2); } } Mapcontroller instance = Mapcontroller.Instance; _indicators = UIScreenIndicators.Create(); _timerUI = TimerUI.CreateAndGet(); bool flag = !LocalGRACEPlugin.IsOutlineColorDefault(); Color color = (Color)(flag ? LocalGRACEPlugin.GetEffectiveOutlineColor() : default(Color)); foreach (GraffitiSpot raceSpot2 in _raceSpots) { ((Component)raceSpot2).gameObject.SetActive(true); _otherSpots.Remove(raceSpot2); _originalProgress[raceSpot2] = GameAPI.GetProgressableData((AProgressable)(object)raceSpot2); GameAPI.GraffitiSpotClearPaint(raceSpot2); raceSpot2.bottomCrew = (Crew)1; if (flag) { ApplyOutlineColorToSpot(raceSpot2, color); } _indicators.AddIndicator(((Component)raceSpot2).transform); MapPin val6 = GameAPI.MapControllerCreatePin(instance, (PinType)2); if ((Object)(object)val6 != (Object)null) { val6.AssignGameplayEvent(((Component)raceSpot2).gameObject); val6.InitMapPin((PinType)2); val6.OnPinEnable(); _mapPins[raceSpot2] = val6; } } Player currentPlayer = WorldHandler.instance.GetCurrentPlayer(); if ((Object)(object)currentPlayer != (Object)null) { currentPlayer.boostCharge = GameAPI.GetPlayerMaxBoostCharge(currentPlayer); GameAPI.SetPlayerUserInputEnabled(currentPlayer, value: false); PlacePlayerAt(_spawnPos, _spawnRot); } _timerUI.Activate(); } public void EndRace(bool cancelled = true) { if (!InGame) { return; } _state = State.Finished; int currentStageId = GameAPI.GetCurrentStageId(); double timeInSeconds = _raceElapsedTime; bool flag = !cancelled; if (currentStageId >= 0 && LocalGRACEPlugin.SaveToStats != null && LocalGRACEPlugin.SaveToStats.Value) { if (flag) { GraceStats.CheckAndUpdateBestTime(currentStageId, timeInSeconds, out var _); } GraceStats.SaveMapStats(currentStageId, timeInSeconds, flag); } Mapcontroller instance = Mapcontroller.Instance; ICollection<MapPin> collection = (((Object)(object)instance != (Object)null) ? GameAPI.GetMapControllerPins(instance) : null); foreach (MapPin value in _mapPins.Values) { if (!((Object)(object)value == (Object)null)) { collection?.Remove(value); GameAPI.SetMapPinValid(value, value: false); GameAPI.MapPinDisable(value); Object.Destroy((Object)(object)((Component)value).gameObject); } } _mapPins.Clear(); if ((Object)(object)_indicators != (Object)null) { Object.Destroy((Object)(object)((Component)_indicators).gameObject); _indicators = null; } RestoreOutlineColors(); _outlineColorBackups.Clear(); foreach (GraffitiSpot otherSpot in _otherSpots) { if ((Object)(object)otherSpot != (Object)null) { ((Component)otherSpot).gameObject.SetActive(true); } } foreach (KeyValuePair<GraffitiSpot, object> item in _originalProgress) { if ((Object)(object)item.Key != (Object)null && item.Value != null) { GameAPI.SetProgressableData((AProgressable)(object)item.Key, item.Value); ((AProgressable)item.Key).ReadFromData(); } } _originalProgress.Clear(); _otherSpots.Clear(); Player currentPlayer = WorldHandler.instance.GetCurrentPlayer(); if ((Object)(object)currentPlayer != (Object)null) { GameAPI.SetPlayerUserInputEnabled(currentPlayer, value: true); } if ((Object)(object)_timerUI != (Object)null) { _timerUI.DeactivateDelayed(); _timerUI = null; } _state = State.None; _raceSpots = null; LocalGRACEPlugin.OnRaceEnded(cancelled); } public void Update() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) if (!InGame) { return; } if (_state == State.Countdown) { _timerUI?.SetMainLabelColor(LocalGRACEPlugin.GetUIColorFromHex(LocalGRACEPlugin.UICountdownTimerColorHex, Color.yellow)); _countdownTimer += Time.deltaTime; int num = Mathf.Max(0, _countdownSeconds - Mathf.FloorToInt(_countdownTimer)); if (num != _lastCountdownRemaining) { _lastCountdownRemaining = num; if (LocalGRACEPlugin.ShowUICountdownTimer != null && LocalGRACEPlugin.ShowUICountdownTimer.Value) { _timerUI?.SetText((num > 0) ? num.ToString() : "GO!"); } else { _timerUI?.SetText(""); } _timerUI?.SetTime(""); } if (_countdownTimer >= (float)_countdownSeconds) { _state = State.Main; _raceElapsedTime = 0f; Player currentPlayer = WorldHandler.instance.GetCurrentPlayer(); if ((Object)(object)currentPlayer != (Object)null) { GameAPI.SetPlayerUserInputEnabled(currentPlayer, value: true); } } } else { if (_state != State.Main) { return; } _timerUI?.SetMainLabelColor(LocalGRACEPlugin.GetUIColorFromHex(LocalGRACEPlugin.UITagCounterColorHex, Color.white)); if (_score < TotalSpots) { _raceElapsedTime += Time.deltaTime; } if (_score != _lastDisplayedScore) { _lastDisplayedScore = _score; if (LocalGRACEPlugin.ShowUITagCounter != null && LocalGRACEPlugin.ShowUITagCounter.Value) { _timerUI?.SetText($"{_score}/{TotalSpots}"); } else { _timerUI?.SetText(""); } } string text = FormatRaceTime(_raceElapsedTime); if (text != _lastFormattedRaceTime) { _lastFormattedRaceTime = text; if (LocalGRACEPlugin.ShowUIRaceTimeTracker != null && LocalGRACEPlugin.ShowUIRaceTimeTracker.Value) { _timerUI?.SetTime(text); } else { _timerUI?.SetTime(""); } } } } private static string FormatRaceTime(float seconds) { int num = Mathf.FloorToInt(seconds / 60f); float num2 = seconds - (float)num * 60f; if (num > 0) { return $"{num}:{num2:00.00}"; } return $"{num2:0.00}"; } public bool IsPartOfRace(GraffitiSpot spot) { if (_originalProgress != null) { return _originalProgress.ContainsKey(spot); } return false; } public bool IsRaceGraffitiSpot(GraffitiSpot spot) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 if (IsPartOfRace(spot)) { return (int)spot.topCrew == 0; } return false; } public void AddScore(GraffitiSpot gSpot) { if (_state == State.Main) { _score++; _lastDisplayedScore = _score; _lastFormattedRaceTime = FormatRaceTime(_raceElapsedTime); MarkGraffitiSpotDone(gSpot); _timerUI?.SetText($"{_score}/{TotalSpots}"); _timerUI?.SetTime(_lastFormattedRaceTime); if (_score >= TotalSpots) { EndRace(cancelled: false); } } } public void MarkGraffitiSpotDone(GraffitiSpot grafSpot) { _indicators?.RemoveIndicator(((Component)grafSpot).transform); if (_mapPins.TryGetValue(grafSpot, out var value)) { GameAPI.GetMapControllerPins(Mapcontroller.Instance)?.Remove(value); GameAPI.SetMapPinValid(value, value: false); GameAPI.MapPinDisable(value); Object.Destroy((Object)(object)((Component)value).gameObject); _mapPins.Remove(grafSpot); } } public int GetValidSpotCount() { return GetValidSpots()?.Count ?? 0; } private List<GraffitiSpot> GetValidSpots() { _worldHandler = WorldHandler.instance; if ((Object)(object)_worldHandler == (Object)null) { return new List<GraffitiSpot>(); } List<GraffitiSpot> grafSpots = GameAPI.GetGrafSpots(_worldHandler); if (grafSpots == null || grafSpots.Count == 0) { return grafSpots ?? new List<GraffitiSpot>(); } return grafSpots.Where(GameAPI.IsValidGraffitiSpotForRace).ToList(); } private void ApplyOutlineColorToSpot(GraffitiSpot spot, Color color) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)spot == (Object)null || (Object)(object)((Component)spot).gameObject == (Object)null) { return; } List<(Renderer, Material, int, Color, Material)> list = new List<(Renderer, Material, int, Color, Material)>(); Renderer[] componentsInChildren = ((Component)spot).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Material material = val.material; if ((Object)(object)material == (Object)null) { continue; } int num = -1; if (material.HasProperty(ShaderPropColor)) { num = ShaderPropColor; } else if (material.HasProperty(ShaderPropBaseColor)) { num = ShaderPropBaseColor; } if (num >= 0) { Color color2 = material.GetColor(num); list.Add((val, material, num, color2, null)); material.SetColor(num, color); continue; } Material val2 = CreateMaterialWithColor(material, color); if ((Object)(object)val2 != (Object)null) { list.Add((val, material, -1, default(Color), val2)); val.material = val2; } } if (list.Count > 0) { _outlineColorBackups[spot] = list; } } private static Material CreateMaterialWithColor(Material source, Color color) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("Unlit/Texture") ?? Shader.Find("Standard") ?? Shader.Find("Legacy Shaders/VertexLit"); if ((Object)(object)val == (Object)null) { return null; } Material val2 = new Material(val); if ((Object)(object)source != (Object)null && source.HasProperty(ShaderPropMainTex)) { Texture texture = source.GetTexture(ShaderPropMainTex); if ((Object)(object)texture != (Object)null && val2.HasProperty(ShaderPropMainTex)) { val2.SetTexture(ShaderPropMainTex, texture); } } if (val2.HasProperty(ShaderPropColor)) { val2.SetColor(ShaderPropColor, color); } else if (val2.HasProperty(ShaderPropBaseColor)) { val2.SetColor(ShaderPropBaseColor, color); } return val2; } private void RestoreOutlineColors() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) foreach (List<(Renderer, Material, int, Color, Material)> value in _outlineColorBackups.Values) { foreach (var (val, val2, num, val3, val4) in value) { if ((Object)(object)val4 != (Object)null) { if ((Object)(object)val != (Object)null) { val.material = val2; } Object.Destroy((Object)(object)val4); } else if ((Object)(object)val2 != (Object)null && num >= 0) { val2.SetColor(num, val3); } } } } private void TurnOnAllStageChunks() { _offStageChunks.Clear(); IList stageChunks = GameAPI.GetStageChunks(WorldHandler.instance); if (stageChunks == null) { return; } foreach (object item in stageChunks) { StageChunk val = (StageChunk)((item is StageChunk) ? item : null); if (val != null && !((Component)val).gameObject.activeSelf) { _offStageChunks.Add(val); ((Component)val).gameObject.SetActive(true); } } } private void RestoreStageChunks() { foreach (StageChunk offStageChunk in _offStageChunks) { if ((Object)(object)offStageChunk != (Object)null) { ((Component)offStageChunk).gameObject.SetActive(false); } } _offStageChunks.Clear(); } private static void PlacePlayerAt(Vector3 position, Quaternion rotation) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) Player currentPlayer = WorldHandler.instance.GetCurrentPlayer(); if (!((Object)(object)currentPlayer == (Object)null)) { currentPlayer.CompletelyStop(); WorldHandler.instance.PlacePlayerAt(currentPlayer, position, rotation, true); currentPlayer.CompletelyStop(); currentPlayer.SetPosAndRotHard(position, rotation); } } } public class TimerUI : MonoBehaviour { private GameObject _canvasGo; private TextMeshProUGUI _label; private TextMeshProUGUI _timeLabel; private TextMeshProUGUI _pbLabel; private TextMeshProUGUI _avgLabel; public void Activate() { ((MonoBehaviour)this).StopAllCoroutines(); if ((Object)(object)_canvasGo != (Object)null) { _canvasGo.SetActive(true); } RefreshPbAvg(); } private void RefreshPbAvg() { int currentStageId = GameAPI.GetCurrentStageId(); double? bestTime = GraceStats.GetBestTime(currentStageId); double? averageTime = GraceStats.GetAverageTime(currentStageId); if ((Object)(object)_pbLabel != (Object)null) { ((TMP_Text)_pbLabel).text = "PB: " + (bestTime.HasValue ? $"{bestTime.Value:F1}s" : "—"); } if ((Object)(object)_avgLabel != (Object)null) { ((TMP_Text)_avgLabel).text = "AVG: " + (averageTime.HasValue ? $"{averageTime.Value:F1}s" : "—"); } } public void Deactivate() { ((MonoBehaviour)this).StopAllCoroutines(); if ((Object)(object)_canvasGo != (Object)null) { _canvasGo.SetActive(false); } } public void DeactivateDelayed() { ((MonoBehaviour)this).StartCoroutine(DeactivateCoroutine()); } private IEnumerator DeactivateCoroutine() { yield return (object)new WaitForSeconds(3f); Deactivate(); } public void SetText(string text) { if ((Object)(object)_label != (Object)null) { ((TMP_Text)_label).text = text; } } public void SetMainLabelColor(Color color) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_label != (Object)null) { ((Graphic)_label).color = color; } } public void SetTime(string timeText) { if ((Object)(object)_timeLabel != (Object)null) { ((TMP_Text)_timeLabel).text = timeText; ((Component)_timeLabel).gameObject.SetActive(!string.IsNullOrEmpty(timeText)); } } private void Awake() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown Core instance = Core.Instance; object obj; if (instance == null) { obj = null; } else { UIManager uIManager = instance.UIManager; obj = ((uIManager != null) ? ((Component)uIManager).transform : null); } Transform val = (Transform)obj; if (!((Object)(object)val == (Object)null)) { _canvasGo = new GameObject("LocalGRACE_TimerCanvas"); _canvasGo.transform.SetParent(val, false); Canvas obj2 = _canvasGo.AddComponent<Canvas>(); obj2.renderMode = (RenderMode)0; obj2.sortingOrder = 100; _canvasGo.AddComponent<CanvasScaler>(); _canvasGo.AddComponent<GraphicRaycaster>(); CreateTMPLabels(); Deactivate(); } } private void CreateTMPLabels() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Expected O, but got Unknown //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Expected O, but got Unknown //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: 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_0320: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Unknown result type (might be due to invalid IL or missing references) //IL_0441: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Timer"); val.transform.SetParent(_canvasGo.transform, false); _label = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_label).text = "0"; ((TMP_Text)_label).fontSize = 72f; ((TMP_Text)_label).fontStyle = (FontStyles)2; ((TMP_Text)_label).alignment = (TextAlignmentOptions)513; ((Graphic)_label).color = LocalGRACEPlugin.GetUIColorFromHex(LocalGRACEPlugin.UITagCounterColorHex, Color.white); RectTransform component = val.GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(0f, 1f); component.pivot = new Vector2(0f, 1f); component.anchoredPosition = new Vector2(24f, -2f); component.sizeDelta = new Vector2(400f, 100f); } GameObject val2 = new GameObject("Time"); val2.transform.SetParent(_canvasGo.transform, false); _timeLabel = val2.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_timeLabel).text = ""; ((TMP_Text)_timeLabel).fontSize = 48f; ((TMP_Text)_timeLabel).fontStyle = (FontStyles)2; ((TMP_Text)_timeLabel).alignment = (TextAlignmentOptions)513; ((Graphic)_timeLabel).color = LocalGRACEPlugin.GetUIColorFromHex(LocalGRACEPlugin.UIRaceTimeTrackerColorHex, new Color(0.85f, 0.85f, 0.85f, 1f)); ((Component)_timeLabel).gameObject.SetActive(false); RectTransform component2 = val2.GetComponent<RectTransform>(); if ((Object)(object)component2 != (Object)null) { component2.anchorMin = new Vector2(0f, 1f); component2.anchorMax = new Vector2(0f, 1f); component2.pivot = new Vector2(0f, 1f); component2.anchoredPosition = new Vector2(24f, -102f); component2.sizeDelta = new Vector2(400f, 60f); } if (LocalGRACEPlugin.ShowUIPB != null && LocalGRACEPlugin.ShowUIPB.Value) { GameObject val3 = new GameObject("PB"); val3.transform.SetParent(_canvasGo.transform, false); _pbLabel = val3.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_pbLabel).text = "PB: —"; ((TMP_Text)_pbLabel).fontSize = 36f; ((TMP_Text)_pbLabel).fontStyle = (FontStyles)2; ((TMP_Text)_pbLabel).alignment = (TextAlignmentOptions)513; ((Graphic)_pbLabel).color = LocalGRACEPlugin.GetUIColorFromHex(LocalGRACEPlugin.UIPBColorHex, Color.green); RectTransform component3 = val3.GetComponent<RectTransform>(); if ((Object)(object)component3 != (Object)null) { component3.anchorMin = new Vector2(0f, 1f); component3.anchorMax = new Vector2(0f, 1f); component3.pivot = new Vector2(0f, 1f); component3.anchoredPosition = new Vector2(24f, -168f); component3.sizeDelta = new Vector2(350f, 44f); } } if (LocalGRACEPlugin.ShowUIAVG != null && LocalGRACEPlugin.ShowUIAVG.Value) { GameObject val4 = new GameObject("AVG"); val4.transform.SetParent(_canvasGo.transform, false); _avgLabel = val4.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_avgLabel).text = "AVG: —"; ((TMP_Text)_avgLabel).fontSize = 36f; ((TMP_Text)_avgLabel).fontStyle = (FontStyles)2; ((TMP_Text)_avgLabel).alignment = (TextAlignmentOptions)513; ((Graphic)_avgLabel).color = LocalGRACEPlugin.GetUIColorFromHex(LocalGRACEPlugin.UIAVGColorHex, Color.yellow); RectTransform component4 = val4.GetComponent<RectTransform>(); if ((Object)(object)component4 != (Object)null) { component4.anchorMin = new Vector2(0f, 1f); component4.anchorMax = new Vector2(0f, 1f); component4.pivot = new Vector2(0f, 1f); component4.anchoredPosition = new Vector2(24f, -218f); component4.sizeDelta = new Vector2(350f, 44f); } } } public static TimerUI CreateAndGet() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) Core instance = Core.Instance; object obj; if (instance == null) { obj = null; } else { UIManager uIManager = instance.UIManager; obj = ((uIManager != null) ? ((Component)uIManager).transform : null); } Transform val = (Transform)obj; if ((Object)(object)val == (Object)null) { return null; } GameObject val2 = new GameObject("LocalGRACE_TimerUI"); val2.transform.SetParent(val, false); return val2.AddComponent<TimerUI>(); } } public class UIScreenIndicators : MonoBehaviour { private float _minDistance = 5f; private float _maxDistance = 20f; private float _distanceSizeMultiplier = 0.5f; private Vector2 _originalSize; private UIManager _uiManager; private GameObject _indicator; private Transform _canvasTf; private Dictionary<Transform, RectTransform> _indicators = new Dictionary<Transform, RectTransform>(); private void Awake() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) _uiManager = Core.Instance.UIManager; _canvasTf = ((Component)this).transform.Find("Canvas"); _indicator = ((Component)_canvasTf.Find("Indicator")).gameObject; RectTransform component = _indicator.GetComponent<RectTransform>(); _originalSize = (Vector2)(((Object)(object)component != (Object)null) ? component.sizeDelta : new Vector2(117.2f, 116.8f)); _indicator.SetActive(false); } private void LateUpdate() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) if (!GameAPI.IsGameplayScreenActive(_uiManager)) { ((Component)_canvasTf).gameObject.SetActive(false); return; } ((Component)_canvasTf).gameObject.SetActive(true); Camera val = GameAPI.GetGameplayCameraCam(); if ((Object)(object)val == (Object)null) { val = Camera.main; } if ((Object)(object)val == (Object)null) { return; } foreach (KeyValuePair<Transform, RectTransform> indicator in _indicators) { Transform key = indicator.Key; RectTransform value = indicator.Value; if (!IsInFront(((Component)val).transform.position, ((Component)val).transform.forward, key.position)) { ((Component)value).gameObject.SetActive(false); continue; } ((Component)value).gameObject.SetActive(true); Vector3 val2 = val.WorldToViewportPoint(key.position); value.anchorMax = Vector2.op_Implicit(val2); value.anchorMin = Vector2.op_Implicit(val2); float num = Vector3.Distance(((Component)val).transform.position, key.position); num -= _minDistance; num /= _maxDistance; num = Mathf.Clamp(num, 0f, 1f); value.sizeDelta = Vector2.Lerp(_originalSize, _originalSize * _distanceSizeMultiplier, num); } } private bool IsInFront(Vector3 cameraPos, Vector3 cameraForward, Vector3 targetPos) { //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_0002: 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) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Vector3 val = targetPos - cameraPos; return Vector3.Dot(cameraForward, val) > 0f; } public void AddIndicator(Transform target) { GameObject val = Object.Instantiate<GameObject>(_indicator); val.transform.SetParent(_canvasTf, false); val.SetActive(true); _indicators[target] = val.GetComponent<RectTransform>(); } public void RemoveIndicator(Transform target) { if (_indicators.TryGetValue(target, out var value)) { _indic