Decompiled source of Speedrun Mod v1.0.0

SpeedrunMod.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("crashout_crew_mod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("crashout_crew_mod")]
[assembly: AssemblyTitle("crashout_crew_mod")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace SpeedrunMod;

[BepInPlugin("com.sialala.speedrun", "Speedrun Mod", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.sialala.speedrun";

		public const string PLUGIN_NAME = "Speedrun Mod";

		public const string PLUGIN_VERSION = "1.0.0";
	}

	public static bool IsTimerRunning = false;

	public static float ElapsedTime = 0f;

	public static TextMeshProUGUI TimerText;

	public static TextMeshProUGUI DeltaText;

	private static GameObject UiCanvasObject;

	public static string CurrentLevelName = "UnknownLevel";

	public static List<float> CurrentSplits = new List<float>();

	public static int CurrentSplitIndex = 0;

	public static bool HasFinishedSplit = false;

	public static List<float> LoadedPBSplits = new List<float>();

	public static List<float> LoadedBestSegments = new List<float>();

	public static ConfigEntry<bool> ConfigEnableTimer;

	public static ConfigEntry<bool> ConfigEnableDelta;

	public static ConfigEntry<bool> ConfigEnableQuickReset;

	public static ConfigEntry<KeyCode> ConfigQuickResetKey;

	public static ConfigEntry<bool> ConfigShowMenuTime;

	public static ConfigEntry<string> ConfigTimerColor;

	public static ConfigEntry<string> ConfigDeltaColorNegative;

	public static ConfigEntry<string> ConfigDeltaColorPositive;

	public static ConfigEntry<string> ConfigDeltaColorGold;

	public static ConfigEntry<string> ConfigMenuTimeColor;

	public static ConfigEntry<int> ConfigTimerFontSize;

	public static ConfigEntry<int> ConfigDeltaFontSize;

	private void Awake()
	{
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Expected O, but got Unknown
		ConfigEnableTimer = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableTimer", true, "Enables or disables the main speedrun timer.");
		ConfigEnableDelta = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableDeltaTimer", true, "Enables or disables live delta comparisons.");
		ConfigEnableQuickReset = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableQuickReset", true, "Enables quick reset shortcut.");
		ConfigQuickResetKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "QuickResetKey", (KeyCode)290, "The key used for quick reset (returns to lobby or restarts run).");
		ConfigShowMenuTime = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowMenuTime", true, "Enables or disables displaying mod PB time in the level selection menu.");
		ConfigTimerColor = ((BaseUnityPlugin)this).Config.Bind<string>("UI.Colors", "TimerColor", "#FFFFFF", "Hex color code for the main timer.");
		ConfigDeltaColorNegative = ((BaseUnityPlugin)this).Config.Bind<string>("UI.Colors", "DeltaColorNegative", "#00FF00", "Hex color code for negative delta (time save).");
		ConfigDeltaColorPositive = ((BaseUnityPlugin)this).Config.Bind<string>("UI.Colors", "DeltaColorPositive", "#FF0000", "Hex color code for positive delta (time loss).");
		ConfigDeltaColorGold = ((BaseUnityPlugin)this).Config.Bind<string>("UI.Colors", "DeltaColorGold", "#FFD700", "Hex color code for a gold split (best segment).");
		ConfigMenuTimeColor = ((BaseUnityPlugin)this).Config.Bind<string>("UI.Colors", "MenuTimeColor", "#9544B7", "Hex color code for the PB time displayed in the level selection menu.");
		ConfigTimerFontSize = ((BaseUnityPlugin)this).Config.Bind<int>("UI.Sizes", "TimerFontSize", 70, "Font size for the main timer.");
		ConfigDeltaFontSize = ((BaseUnityPlugin)this).Config.Bind<int>("UI.Sizes", "DeltaFontSize", 50, "Font size for the live delta timer.");
		SceneManager.sceneLoaded += OnSceneLoaded;
		Harmony val = new Harmony("com.sialala.speedrun");
		val.PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Mod Speedrun Mod loaded and Harmony injected");
	}

	public static string FormatTime(float timeInSeconds)
	{
		TimeSpan timeSpan = TimeSpan.FromSeconds(timeInSeconds);
		return $"{Math.Floor(timeSpan.TotalMinutes):00}:{timeSpan.Seconds:00}:{timeSpan.Milliseconds / 10:00}";
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Expected O, but got Unknown
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Expected O, but got Unknown
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_021b: Unknown result type (might be due to invalid IL or missing references)
		//IL_023c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Expected O, but got Unknown
		//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_031c: Unknown result type (might be due to invalid IL or missing references)
		//IL_033c: Unknown result type (might be due to invalid IL or missing references)
		ElapsedTime = 0f;
		IsTimerRunning = false;
		CurrentSplitIndex = 0;
		HasFinishedSplit = false;
		CurrentSplits.Clear();
		LoadedPBSplits.Clear();
		LoadedBestSegments.Clear();
		if ((Object)(object)UiCanvasObject != (Object)null)
		{
			if ((Object)(object)TimerText != (Object)null)
			{
				((TMP_Text)TimerText).text = "00:00:00";
				((Component)TimerText).gameObject.SetActive(false);
			}
			if ((Object)(object)DeltaText != (Object)null)
			{
				((TMP_Text)DeltaText).text = "";
				((Component)DeltaText).gameObject.SetActive(false);
			}
			return;
		}
		UiCanvasObject = new GameObject("ModTimerCanvas");
		Canvas val = UiCanvasObject.AddComponent<Canvas>();
		val.renderMode = (RenderMode)0;
		val.sortingOrder = 999;
		UiCanvasObject.AddComponent<CanvasScaler>();
		UiCanvasObject.AddComponent<GraphicRaycaster>();
		UiCanvasObject.AddComponent<TimerUpdater>();
		Object.DontDestroyOnLoad((Object)(object)UiCanvasObject);
		GameObject val2 = new GameObject("ModTimerText");
		val2.transform.SetParent(UiCanvasObject.transform, false);
		TimerText = val2.AddComponent<TextMeshProUGUI>();
		((TMP_Text)TimerText).text = "00:00:00";
		((TMP_Text)TimerText).fontSize = ConfigTimerFontSize.Value;
		Color color = default(Color);
		ColorUtility.TryParseHtmlString(ConfigTimerColor.Value, ref color);
		((Graphic)TimerText).color = color;
		((TMP_Text)TimerText).alignment = (TextAlignmentOptions)1025;
		((TMP_Text)TimerText).enableWordWrapping = false;
		RectTransform component = ((Component)TimerText).GetComponent<RectTransform>();
		component.anchorMin = new Vector2(0f, 0f);
		component.anchorMax = new Vector2(0f, 0f);
		component.pivot = new Vector2(0f, 0f);
		component.anchoredPosition = new Vector2(20f, 20f);
		component.sizeDelta = new Vector2(500f, (float)(ConfigTimerFontSize.Value + 20));
		((Component)TimerText).gameObject.SetActive(false);
		GameObject val3 = new GameObject("ModDeltaText");
		val3.transform.SetParent(UiCanvasObject.transform, false);
		DeltaText = val3.AddComponent<TextMeshProUGUI>();
		((TMP_Text)DeltaText).text = "";
		((TMP_Text)DeltaText).fontSize = ConfigDeltaFontSize.Value;
		((TMP_Text)DeltaText).alignment = (TextAlignmentOptions)1025;
		((TMP_Text)DeltaText).enableWordWrapping = false;
		RectTransform component2 = ((Component)DeltaText).GetComponent<RectTransform>();
		component2.anchorMin = new Vector2(0f, 0f);
		component2.anchorMax = new Vector2(0f, 0f);
		component2.pivot = new Vector2(0f, 0f);
		float num = 20f + (float)ConfigTimerFontSize.Value + 10f;
		component2.anchoredPosition = new Vector2(20f, num);
		component2.sizeDelta = new Vector2(500f, (float)(ConfigDeltaFontSize.Value + 20));
		((Component)DeltaText).gameObject.SetActive(false);
		Debug.Log((object)"[SpeedrunMod] Timer UI successfully injected into the scene.");
	}
}
public class TimerUpdater : MonoBehaviour
{
	private void Update()
	{
		//IL_0301: Unknown result type (might be due to invalid IL or missing references)
		//IL_035b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0331: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: 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)
		if ((Object)(object)Plugin.TimerText != (Object)null && !Plugin.ConfigEnableTimer.Value)
		{
			if (((Component)Plugin.TimerText).gameObject.activeSelf)
			{
				((Component)Plugin.TimerText).gameObject.SetActive(false);
			}
			if ((Object)(object)Plugin.DeltaText != (Object)null && ((Component)Plugin.DeltaText).gameObject.activeSelf)
			{
				((Component)Plugin.DeltaText).gameObject.SetActive(false);
			}
		}
		if (Plugin.IsTimerRunning && (Object)(object)Plugin.TimerText != (Object)null)
		{
			Plugin.ElapsedTime += Time.deltaTime;
			((TMP_Text)Plugin.TimerText).text = Plugin.FormatTime(Plugin.ElapsedTime);
			if (Plugin.ConfigEnableTimer.Value && Plugin.ConfigEnableDelta.Value)
			{
				if (!Plugin.HasFinishedSplit && (Object)(object)Plugin.DeltaText != (Object)null && Plugin.LoadedPBSplits != null && Plugin.CurrentSplitIndex < Plugin.LoadedPBSplits.Count)
				{
					float num = Plugin.LoadedPBSplits[Plugin.CurrentSplitIndex];
					float num2 = ((Plugin.LoadedBestSegments.Count > Plugin.CurrentSplitIndex) ? Plugin.LoadedBestSegments[Plugin.CurrentSplitIndex] : float.MaxValue);
					float num3 = ((Plugin.CurrentSplitIndex == 0) ? Plugin.ElapsedTime : (Plugin.ElapsedTime - Plugin.CurrentSplits[Plugin.CurrentSplitIndex - 1]));
					float value = Plugin.ElapsedTime - num;
					if (Plugin.ElapsedTime > num)
					{
						((TMP_Text)Plugin.DeltaText).text = "+" + Plugin.FormatTime(Math.Abs(value));
						Color color = default(Color);
						if (ColorUtility.TryParseHtmlString(Plugin.ConfigDeltaColorPositive.Value, ref color))
						{
							((Graphic)Plugin.DeltaText).color = color;
						}
						if (!((Component)Plugin.DeltaText).gameObject.activeSelf)
						{
							((Component)Plugin.DeltaText).gameObject.SetActive(true);
						}
					}
					else if (num3 > num2)
					{
						((TMP_Text)Plugin.DeltaText).text = "-" + Plugin.FormatTime(Math.Abs(value));
						Color color2 = default(Color);
						if (ColorUtility.TryParseHtmlString(Plugin.ConfigDeltaColorNegative.Value, ref color2))
						{
							((Graphic)Plugin.DeltaText).color = color2;
						}
						if (!((Component)Plugin.DeltaText).gameObject.activeSelf)
						{
							((Component)Plugin.DeltaText).gameObject.SetActive(true);
						}
					}
					else if (((Component)Plugin.DeltaText).gameObject.activeSelf)
					{
						((Component)Plugin.DeltaText).gameObject.SetActive(false);
					}
				}
			}
			else if ((Object)(object)Plugin.DeltaText != (Object)null && ((Component)Plugin.DeltaText).gameObject.activeSelf)
			{
				((Component)Plugin.DeltaText).gameObject.SetActive(false);
			}
		}
		if (Plugin.ConfigEnableQuickReset.Value && Input.GetKeyDown(Plugin.ConfigQuickResetKey.Value))
		{
			if (GameUtil.isLobby)
			{
				GameManager.NextRun();
				Debug.Log((object)$"[SpeedrunMod] Quick start from Lobby ({Plugin.ConfigQuickResetKey.Value})!");
			}
			else
			{
				GameManager.Next((GameNextType)1);
				Debug.Log((object)$"[SpeedrunMod] Run aborted! Safe return to Lobby ({Plugin.ConfigQuickResetKey.Value}).");
			}
		}
	}
}
public static class SplitsManager
{
	public static string SaveFilePath => Path.Combine(Paths.PluginPath, "SpeedrunSplits.json");

	public static SplitsSaveFile LoadSplits()
	{
		if (!File.Exists(SaveFilePath))
		{
			Debug.Log((object)"[SpeedrunMod] No existing splits file found. Creating a new one.");
			return new SplitsSaveFile();
		}
		try
		{
			string text = File.ReadAllText(SaveFilePath);
			return JsonConvert.DeserializeObject<SplitsSaveFile>(text) ?? new SplitsSaveFile();
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[SpeedrunMod] Error loading splits: " + ex.Message));
			return new SplitsSaveFile();
		}
	}

	public static void SaveSplits(SplitsSaveFile data)
	{
		try
		{
			string contents = JsonConvert.SerializeObject((object)data, (Formatting)1);
			File.WriteAllText(SaveFilePath, contents);
			Debug.Log((object)"[SpeedrunMod] Splits saved successfully.");
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[SpeedrunMod] Failed to save splits: " + ex.Message));
		}
	}

	public static void LoadLevelDataIntoMemory(string levelName)
	{
		Plugin.LoadedPBSplits.Clear();
		Plugin.LoadedBestSegments.Clear();
		SplitsSaveFile splitsSaveFile = LoadSplits();
		SplitRecord splitRecord = splitsSaveFile.records.Find((SplitRecord r) => r.levelName == levelName);
		if (splitRecord != null)
		{
			if (splitRecord.pbSplits != null)
			{
				Plugin.LoadedPBSplits = new List<float>(splitRecord.pbSplits);
			}
			if (splitRecord.bestSegments != null)
			{
				Plugin.LoadedBestSegments = new List<float>(splitRecord.bestSegments);
			}
		}
		if (splitRecord != null)
		{
			Debug.Log((object)("[SpeedrunMod] Loaded PB data for " + levelName + ". Total time to beat: " + Plugin.FormatTime(splitRecord.totalTime)));
		}
		else
		{
			Debug.Log((object)("[SpeedrunMod] No previous PB found for " + levelName + ". This is a new run!"));
		}
	}

	public static void ProcessAndSaveRun(string levelName, List<float> runSplits, bool isRunCompleted)
	{
		if (runSplits.Count == 0 || string.IsNullOrEmpty(levelName) || levelName == "UnknownLevel")
		{
			return;
		}
		SplitsSaveFile splitsSaveFile = LoadSplits();
		SplitRecord splitRecord = splitsSaveFile.records.Find((SplitRecord r) => r.levelName == levelName);
		bool flag = false;
		if (splitRecord == null)
		{
			splitRecord = new SplitRecord
			{
				levelName = levelName,
				totalTime = float.MaxValue
			};
			splitsSaveFile.records.Add(splitRecord);
			flag = true;
		}
		if (splitRecord.bestSegments == null)
		{
			splitRecord.bestSegments = new List<float>();
		}
		if (splitRecord.pbSplits == null)
		{
			splitRecord.pbSplits = new List<float>();
		}
		for (int num = 0; num < runSplits.Count; num++)
		{
			float num2 = runSplits[num];
			if (num > 0)
			{
				num2 -= runSplits[num - 1];
			}
			if (splitRecord.bestSegments.Count <= num)
			{
				splitRecord.bestSegments.Add(num2);
				flag = true;
			}
			else if (num2 < splitRecord.bestSegments[num])
			{
				splitRecord.bestSegments[num] = num2;
				flag = true;
				Debug.Log((object)$"[SpeedrunMod] GOLD SPLIT! Shift {num + 1} completed in {num2:F2}s");
			}
		}
		if (isRunCompleted)
		{
			float num3 = runSplits[runSplits.Count - 1];
			if (num3 < splitRecord.totalTime)
			{
				splitRecord.totalTime = num3;
				splitRecord.pbSplits = new List<float>(runSplits);
				flag = true;
				Debug.Log((object)$"[SpeedrunMod] NEW PB! Total time: {num3:F2}s");
			}
		}
		if (flag)
		{
			SaveSplits(splitsSaveFile);
		}
	}
}
[HarmonyPatch(typeof(ShiftManager))]
public class ShiftManagerPatches
{
	[HarmonyPatch("ShiftChanged")]
	[HarmonyPostfix]
	public static void Postfix_ShiftChanged(ShiftPhase phase, int shift, int outboundsRequired)
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Invalid comparison between Unknown and I4
		if ((Object)(object)Plugin.TimerText != (Object)null && !((Component)Plugin.TimerText).gameObject.activeSelf && Plugin.ConfigEnableTimer.Value)
		{
			((Component)Plugin.TimerText).gameObject.SetActive(true);
		}
		if ((int)phase == 3)
		{
			Plugin.HasFinishedSplit = false;
			if ((Object)(object)Plugin.DeltaText != (Object)null)
			{
				((Component)Plugin.DeltaText).gameObject.SetActive(false);
			}
			if (shift == 1 && !Plugin.IsTimerRunning && Plugin.ElapsedTime < 0.1f && (Object)(object)GameUtil.contract != (Object)null)
			{
				Plugin.CurrentLevelName = ((Object)GameUtil.contract).name;
				SplitsManager.LoadLevelDataIntoMemory(Plugin.CurrentLevelName);
				Debug.Log((object)("[SpeedrunMod] Started: " + Plugin.CurrentLevelName));
			}
			Plugin.IsTimerRunning = true;
		}
		else
		{
			Plugin.IsTimerRunning = false;
		}
	}

	private static void RecordSplit(byte shiftCount, bool isRunCompleted)
	{
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		Debug.Log((object)$"[SpeedrunMod] Shift {shiftCount} completed at {Plugin.FormatTime(Plugin.ElapsedTime)}");
		Plugin.IsTimerRunning = false;
		int count = Plugin.CurrentSplits.Count;
		Plugin.CurrentSplits.Add(Plugin.ElapsedTime);
		if (Plugin.ConfigEnableTimer.Value && Plugin.ConfigEnableDelta.Value && Plugin.LoadedPBSplits != null && count < Plugin.LoadedPBSplits.Count)
		{
			float num = Plugin.LoadedPBSplits[count];
			float num2 = Plugin.ElapsedTime - num;
			float num3 = ((count == 0) ? Plugin.ElapsedTime : (Plugin.ElapsedTime - Plugin.CurrentSplits[count - 1]));
			bool flag = false;
			if (Plugin.LoadedBestSegments != null && count < Plugin.LoadedBestSegments.Count && num3 < Plugin.LoadedBestSegments[count])
			{
				flag = true;
			}
			string text = ((num2 > 0f) ? "+" : "-");
			((TMP_Text)Plugin.DeltaText).text = text + Plugin.FormatTime(Math.Abs(num2));
			Color color3 = default(Color);
			if (flag)
			{
				Color color = default(Color);
				if (ColorUtility.TryParseHtmlString(Plugin.ConfigDeltaColorGold.Value, ref color))
				{
					((Graphic)Plugin.DeltaText).color = color;
				}
			}
			else if (num2 <= 0f)
			{
				Color color2 = default(Color);
				if (ColorUtility.TryParseHtmlString(Plugin.ConfigDeltaColorNegative.Value, ref color2))
				{
					((Graphic)Plugin.DeltaText).color = color2;
				}
			}
			else if (ColorUtility.TryParseHtmlString(Plugin.ConfigDeltaColorPositive.Value, ref color3))
			{
				((Graphic)Plugin.DeltaText).color = color3;
			}
			((Component)Plugin.DeltaText).gameObject.SetActive(true);
			Plugin.HasFinishedSplit = true;
		}
		else if ((Object)(object)Plugin.DeltaText != (Object)null)
		{
			((Component)Plugin.DeltaText).gameObject.SetActive(false);
		}
		Plugin.CurrentSplitIndex = Plugin.CurrentSplits.Count;
		SplitsManager.ProcessAndSaveRun(Plugin.CurrentLevelName, Plugin.CurrentSplits, isRunCompleted);
	}

	[HarmonyPatch("UserCode_RpcTransitionShiftToShiftWon__Byte__ContractScore__Vector3")]
	[HarmonyPostfix]
	public static void StopTimer_ShiftWon(byte shiftCount)
	{
		RecordSplit(shiftCount, isRunCompleted: false);
	}

	[HarmonyPatch("UserCode_RpcTransitionShiftToShiftWonPhase1__Byte__ContractScore__Vector3")]
	[HarmonyPostfix]
	public static void StopTimer_ShiftWonPhase1(byte shiftCount)
	{
		RecordSplit(shiftCount, isRunCompleted: false);
	}

	[HarmonyPatch("UserCode_RpcTransitionShiftToGameWon__Byte__ContractScore__ContractScore__Int32__Vector3__PlayerResult[]")]
	[HarmonyPostfix]
	public static void StopTimer_GameWon(byte shiftCount)
	{
		RecordSplit(shiftCount, isRunCompleted: true);
	}

	[HarmonyPatch("UserCode_RpcTransitionShiftToGameLost__Byte__Int32__Vector3__PlayerResult[]")]
	[HarmonyPostfix]
	public static void StopTimer_GameLost(byte shiftCount)
	{
		Plugin.IsTimerRunning = false;
		Debug.Log((object)"[SpeedrunMod] Run lost! Timer stopped. Splits ignored.");
	}
}
[HarmonyPatch(typeof(ContractSelectionUI))]
public class ContractSelectionUIPatches
{
	[HarmonyPatch("SetUp")]
	[HarmonyPostfix]
	public static void Postfix_SetUp(ContractSelectionUI __instance)
	{
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Invalid comparison between Unknown and I4
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Expected O, but got Unknown
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Invalid comparison between Unknown and I4
		//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.ConfigShowMenuTime.Value)
		{
			return;
		}
		SplitsSaveFile splitsSaveFile = SplitsManager.LoadSplits();
		for (int i = 0; i < __instance._contracts.Count; i++)
		{
			ContractObject contract = __instance._contracts[i];
			if (i >= __instance.contractGroup.childCount)
			{
				continue;
			}
			ContractUI component = ((Component)__instance.contractGroup.GetChild(i)).GetComponent<ContractUI>();
			if (!((Object)(object)component != (Object)null))
			{
				continue;
			}
			SplitRecord splitRecord = splitsSaveFile.records.Find((SplitRecord r) => r.levelName == ((Object)contract).name);
			if (splitRecord == null || !(splitRecord.totalTime < float.MaxValue))
			{
				continue;
			}
			string text = Plugin.FormatTime(splitRecord.totalTime);
			Transform val = (((int)contract.type != 1) ? ((TMP_Text)component.bestTimeText).transform.parent : ((Component)component).transform);
			Transform val2 = val.Find("ModSpeedrunText");
			TextMeshProUGUI val5;
			if ((Object)(object)val2 == (Object)null)
			{
				GameObject val3 = new GameObject("ModSpeedrunText");
				val3.transform.SetParent(val, false);
				RectTransform val4 = val3.AddComponent<RectTransform>();
				val5 = val3.AddComponent<TextMeshProUGUI>();
				RectTransform component2 = ((Component)component.bestTimeText).GetComponent<RectTransform>();
				val4.anchorMin = component2.anchorMin;
				val4.anchorMax = component2.anchorMax;
				val4.pivot = component2.pivot;
				val4.sizeDelta = new Vector2(component2.sizeDelta.x * 1.5f, 150f);
				if ((int)contract.type == 1)
				{
					val4.anchoredPosition = component2.anchoredPosition + new Vector2(95f, -350f);
				}
				else
				{
					val4.anchoredPosition = component2.anchoredPosition + new Vector2(65f, -110f);
				}
				((TMP_Text)val5).font = ((TMP_Text)component.bestTimeText).font;
				((TMP_Text)val5).fontSize = 60f;
				((TMP_Text)val5).alignment = (TextAlignmentOptions)257;
				((TMP_Text)val5).enableAutoSizing = false;
				((TMP_Text)val5).overflowMode = (TextOverflowModes)0;
			}
			else
			{
				val5 = ((Component)val2).GetComponent<TextMeshProUGUI>();
			}
			((TMP_Text)val5).text = "<color=" + Plugin.ConfigMenuTimeColor.Value + "><b>" + text + "</b></color>";
		}
	}
}
[Serializable]
public class SplitRecord
{
	public string levelName;

	public float totalTime;

	public List<float> pbSplits = new List<float>();

	public List<float> bestSegments = new List<float>();
}
[Serializable]
public class SplitsSaveFile
{
	public List<SplitRecord> records = new List<SplitRecord>();
}