Decompiled source of Split Stats Speedrunning Timer v1.4.0

SplitsStats.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Peak;
using Photon.Pun;
using TMPro;
using TerrainRandomiser;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core;

[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("SplitsStats")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyInformationalVersion("1.4.0")]
[assembly: AssemblyProduct("Splits Stats")]
[assembly: AssemblyTitle("SplitsStats")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SplitsStats
{
	public class AnimationManager : MonoBehaviour
	{
		private static int timersCurrentlyAnimated;

		public static bool AreTimersCurrentlyAnimated()
		{
			return timersCurrentlyAnimated > 0;
		}

		public static float CubicInterpolation(float a, float b, float t, float centralVelocity = 1.5f)
		{
			float num = (b - a) * centralVelocity;
			float num2 = t * t * t;
			float num3 = t * t;
			if (t < 0.5f)
			{
				float num4 = 8f * a - 8f * b + 4f * num;
				float num5 = -6f * a + 6f * b - 2f * num;
				return num4 * num2 + num5 * num3 + a;
			}
			float num6 = 8f * a - 8f * b + 4f * num;
			float num7 = -18f * a + 18f * b - 10f * num;
			float num8 = 12f * a - 12f * b + 8f * num;
			float num9 = -2f * a + 3f * b - 2f * num;
			return num6 * num2 + num7 * num3 + num8 * t + num9;
		}

		public void LerpTimerFontSize(TimerComponent timer, float newFontSize, float duration)
		{
			((MonoBehaviour)this).StartCoroutine(LerpTimerFontSizeCoroutine(timer, newFontSize, duration));
		}

		public IEnumerator LerpTimerFontSizeCoroutine(TimerComponent timer, float newFontSize, float duration)
		{
			if (!((Object)(object)timer == (Object)null) && !(newFontSize < 0f))
			{
				timersCurrentlyAnimated++;
				float initialFontSize = timer.GetHeight();
				float startingTime = Time.time;
				while (Time.time - startingTime < duration)
				{
					float currFontSize = CubicInterpolation(initialFontSize, newFontSize, (Time.time - startingTime) / duration, 2.5f);
					timer.SetHeight(currFontSize);
					yield return null;
				}
				timer.SetHeight(newFontSize);
				timersCurrentlyAnimated--;
			}
		}
	}
	public abstract class BaseUIComponent : MonoBehaviour, IComparable<BaseUIComponent>
	{
		public UIComponentPosition uiPosition;

		private bool _hidden;

		public const float INITIAL_HEIGHT = 100f;

		private int _priority;

		internal BaseUIComponentList inInfoList = null;

		public RectTransform rectTransform => GetRectTransform();

		public virtual bool IsHidden
		{
			get
			{
				return _hidden;
			}
			set
			{
				_hidden = value;
				SplitsManager.Instance?.UpdateTimerPositions();
			}
		}

		public static T CreateUIComponent<T>(string name, Transform parent = null) where T : BaseUIComponent
		{
			return CreateBaseUIComponent<T>(name, parent);
		}

		public static T CreateBaseUIComponent<T>(string name, Transform parent = null) where T : BaseUIComponent
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(T)
			});
			T component = val.GetComponent<T>();
			if ((Object)(object)parent != (Object)null)
			{
				val.transform.SetParent(parent);
			}
			return component;
		}

		public BaseUIComponent()
		{
			uiPosition = UIComponentPosition.TopRight;
			IsHidden = false;
			_priority = 0;
		}

		public virtual void Start()
		{
			//IL_0007: 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)
			rectTransform.anchoredPosition = Vector2.zero;
			rectTransform.sizeDelta = new Vector2(0f, 100f);
		}

		public virtual void SetHeight(float newSize)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.localScale = new Vector3(newSize / 100f, newSize / 100f, 1f);
		}

		public virtual float GetHeight()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return ((Component)this).transform.localScale.y * 100f;
		}

		public virtual bool GetHidden()
		{
			return IsHidden;
		}

		public virtual void SetHidden(bool isHidden)
		{
			IsHidden = isHidden;
		}

		public virtual RectTransform GetRectTransform()
		{
			return ((Component)this).gameObject.GetComponent<RectTransform>();
		}

		public void SetSortingPriority(int priority)
		{
			inInfoList?.Reorder(this);
			_priority = priority;
		}

		public int CompareTo(BaseUIComponent other)
		{
			return _priority - other._priority;
		}
	}
	public class BaseUIComponentList : IList<BaseUIComponent>, ICollection<BaseUIComponent>, IEnumerable<BaseUIComponent>, IEnumerable
	{
		private List<BaseUIComponent> _baseUIComponents;

		public bool IsFixedSize => false;

		public bool IsReadOnly => false;

		public int Count => _baseUIComponents.Count;

		public bool IsSynchronized => false;

		public BaseUIComponent SyncRoot
		{
			get
			{
				throw new NotImplementedException();
			}
		}

		public BaseUIComponent this[int index]
		{
			get
			{
				return _baseUIComponents[index];
			}
			set
			{
				throw new NotSupportedException("Setting via the indexor is not supported to maintain a sorted order of elements! Use the Delete(BaseUIComponent original) then Add(BaseUIComponent value) method instead!");
			}
		}

		public BaseUIComponentList()
		{
			_baseUIComponents = new List<BaseUIComponent>();
		}

		internal void Reorder(BaseUIComponent element)
		{
			if (Contains(element))
			{
				Remove(element);
				Add(element);
			}
		}

		public void Add(BaseUIComponent value)
		{
			value.inInfoList = this;
			int i = _baseUIComponents.BinarySearch(value);
			if (i >= 0)
			{
				if ((Object)(object)_baseUIComponents[i] == (Object)(object)value)
				{
					return;
				}
				for (; i < Count && _baseUIComponents[i].CompareTo(value) == 0; i++)
				{
				}
			}
			else
			{
				i = ~i;
			}
			_baseUIComponents.Insert(i, value);
		}

		public void Clear()
		{
			_baseUIComponents.Clear();
		}

		public bool Contains(BaseUIComponent value)
		{
			return _baseUIComponents.Contains(value);
		}

		public int IndexOf(BaseUIComponent value)
		{
			return _baseUIComponents.IndexOf(value);
		}

		public void Insert(int index, BaseUIComponent value)
		{
			throw new NotSupportedException("Inserting is not supported to maintain a sorted order of elements! Use the Add(BaseUIComponent value) method instead!");
		}

		public bool Remove(BaseUIComponent item)
		{
			bool flag = _baseUIComponents.Remove(item);
			if (flag)
			{
				item.inInfoList = null;
			}
			return flag;
		}

		public void RemoveAt(int index)
		{
			_baseUIComponents[index].inInfoList = null;
			_baseUIComponents.RemoveAt(index);
		}

		public void CopyTo(BaseUIComponent[] array, int arrayIndex)
		{
			_baseUIComponents.CopyTo(array, arrayIndex);
		}

		public IEnumerator GetEnumerator()
		{
			return _baseUIComponents.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return _baseUIComponents.GetEnumerator();
		}

		IEnumerator<BaseUIComponent> IEnumerable<BaseUIComponent>.GetEnumerator()
		{
			return _baseUIComponents.GetEnumerator();
		}
	}
	public enum UIComponentPosition
	{
		TopLeft,
		TopRight
	}
	public class InfoComponentTemplate
	{
		public string name;

		public Func<string> TextToDisplay;

		public Sprite icon = null;

		public float initialFontSize = 32f;

		public UIComponentPosition position = UIComponentPosition.TopRight;

		public int priority = 0;

		public Color color;

		public bool isHidden;

		private static Color defaultColor = new Color(0.9f, 0.9f, 0.9f);

		private string DefaultNullOutput()
		{
			return null;
		}

		public InfoComponentTemplate(string name, Func<string> TextToDisplay = null, Sprite icon = null, float initialFontSize = 32f, UIComponentPosition position = UIComponentPosition.TopRight, Color? color = null, bool isHidden = false, int priority = 0)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			this.name = name;
			this.TextToDisplay = TextToDisplay ?? new Func<string>(DefaultNullOutput);
			this.icon = icon;
			this.initialFontSize = initialFontSize;
			this.position = position;
			this.color = (color.HasValue ? color.Value : defaultColor);
			this.isHidden = isHidden;
			this.priority = priority;
		}

		public InfoComponentTemplate(InfoComponentTemplate original)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			name = original.name;
			TextToDisplay = original.TextToDisplay;
			icon = original.icon;
			initialFontSize = original.initialFontSize;
			position = original.position;
			color = original.color;
			isHidden = original.isHidden;
			priority = original.priority;
		}
	}
	public class InfoComponent : BaseUIComponent
	{
		public RectTransform textRectTransform;

		public RectTransform iconRectTransform;

		public Func<string> TextToDisplay;

		private Color currColor = new Color(0.9f, 0.9f, 0.9f);

		private static RectTransform _templateTextObject;

		private static RectTransform _templateIconObject;

		public InfoComponentTemplate template;

		public Image iconImage
		{
			get
			{
				RectTransform obj = iconRectTransform;
				return (obj != null) ? ((Component)obj).GetComponent<Image>() : null;
			}
		}

		public TMP_Text tmpText
		{
			get
			{
				RectTransform obj = textRectTransform;
				return (obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null;
			}
		}

		public static RectTransform templateTextObject
		{
			get
			{
				if ((Object)(object)_templateTextObject == (Object)null)
				{
					GetTemplateObjects();
				}
				return _templateTextObject;
			}
			private set
			{
				_templateTextObject = value;
			}
		}

		public static RectTransform templateIconObject
		{
			get
			{
				if ((Object)(object)_templateIconObject == (Object)null)
				{
					GetTemplateObjects();
				}
				return _templateIconObject;
			}
			private set
			{
				_templateIconObject = value;
			}
		}

		private static void GetTemplateObjects()
		{
			//IL_0004: 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)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: 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_0165: 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: Expected O, but got Unknown
			RectTransform val = null;
			Scene activeScene = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
			foreach (GameObject val2 in rootGameObjects)
			{
				AscentUI componentInChildren = val2.GetComponentInChildren<AscentUI>();
				val = ((componentInChildren != null) ? ((Component)componentInChildren).GetComponent<RectTransform>() : null);
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				throw new MissingReferenceException("Could not find an AscentUI object to use for a text template!");
			}
			templateTextObject = Object.Instantiate<RectTransform>(val, ((Transform)val).parent);
			((Object)templateTextObject).name = "InfoComponent Template Text";
			Object.Destroy((Object)(object)((Component)templateTextObject).GetComponent<AscentUI>());
			templateTextObject.offsetMin = Vector2.zero;
			templateTextObject.offsetMax = Vector2.zero;
			RectTransform val3 = null;
			activeScene = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects2 = ((Scene)(ref activeScene)).GetRootGameObjects();
			foreach (GameObject val4 in rootGameObjects2)
			{
				Image[] componentsInChildren = val4.GetComponentsInChildren<Image>();
				foreach (Image val5 in componentsInChildren)
				{
					Transform transform = ((Component)val5).transform;
					if (((Object)transform).name == "Icon" && ((Object)transform.parent).name == "ExtraStaminaBar")
					{
						val3 = (RectTransform)transform;
						break;
					}
				}
			}
			if ((Object)(object)val3 == (Object)null)
			{
				throw new MissingReferenceException("Could not find the stamina icon object to use for an icon template!");
			}
			templateIconObject = Object.Instantiate<RectTransform>(val3, ((Transform)val).parent);
			((Object)templateIconObject).name = "InfoComponent Template Icon";
			templateIconObject.sizeDelta = new Vector2(200f, 200f);
			templateIconObject.offsetMin = Vector2.zero;
			templateIconObject.offsetMax = Vector2.zero;
			templateIconObject.anchoredPosition = Vector2.zero;
			((Component)templateTextObject).gameObject.SetActive(false);
			((Component)templateIconObject).gameObject.SetActive(false);
		}

		public static InfoComponent CreateInfoComponent(InfoComponentTemplate template, Transform parent = null)
		{
			return CreateInfoComponent<InfoComponent>(template, parent);
		}

		public static T CreateInfoComponent<T>(InfoComponentTemplate template, Transform parent = null) where T : InfoComponent
		{
			T val = BaseUIComponent.CreateBaseUIComponent<T>(template.name, parent);
			val.template = new InfoComponentTemplate(template);
			val.SetSortingPriority(template.priority);
			val.uiPosition = template.position;
			return val;
		}

		public override void Start()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			base.Start();
			SplitsManager.SetAlignment(base.rectTransform, uiPosition);
			base.rectTransform.pivot = new Vector2(base.rectTransform.pivot.x, 1f);
			if ((Object)(object)textRectTransform == (Object)null || (Object)(object)((Component)textRectTransform).GetComponent<RectTransform>() == (Object)null || (Object)(object)((Component)textRectTransform).GetComponent<TMP_Text>() == (Object)null)
			{
				if (template == null)
				{
					throw new ArgumentNullException("An InfoComponentTemplate template is required to create the default text object! Please ensure this.template is set prior to the Awake() call!");
				}
				RectTransform obj = textRectTransform;
				if (obj != null)
				{
					((Component)obj).gameObject.SetActive(false);
				}
				RectTransform val = Object.Instantiate<RectTransform>(templateTextObject, ((Component)this).gameObject.transform);
				((Component)val).gameObject.SetActive(true);
				((Object)val).name = template.name + " Text";
				val.anchoredPosition = Vector2.zero;
				SplitsManager.SetAlignment(val, uiPosition);
				foreach (Transform item in ((Component)val).transform)
				{
					Transform val2 = item;
					Object.Destroy((Object)(object)((Component)val2).gameObject);
				}
				textRectTransform = val;
			}
			if ((Object)(object)iconRectTransform == (Object)null || (Object)(object)((Component)iconRectTransform).GetComponent<RectTransform>() == (Object)null || (Object)(object)((Component)iconRectTransform).GetComponent<Image>() == (Object)null)
			{
				if (template == null)
				{
					throw new ArgumentNullException("An InfoComponentTemplate template is required to create the default icon object! Please ensure this.template is set prior to the Awake() call!");
				}
				RectTransform obj2 = iconRectTransform;
				if (obj2 != null)
				{
					((Component)obj2).gameObject.SetActive(false);
				}
				if ((Object)(object)templateIconObject != (Object)null && (Object)(object)template.icon != (Object)null)
				{
					RectTransform val3 = Object.Instantiate<RectTransform>(templateIconObject, ((Component)this).gameObject.transform);
					((Component)val3).gameObject.SetActive(true);
					((Object)val3).name = template.name + " Icon";
					val3.sizeDelta = new Vector2(110f, 110f);
					val3.anchoredPosition = Vector2.zero;
					SplitsManager.SetAlignment(val3, uiPosition);
					val3.pivot += new Vector2(0f, 0.100000024f);
					((Component)val3).GetComponent<Image>().sprite = template.icon;
					iconRectTransform = val3;
					float x = val3.sizeDelta.x;
					int num = ((uiPosition == UIComponentPosition.TopLeft) ? 1 : (-1));
					RectTransform obj3 = textRectTransform;
					obj3.anchoredPosition += new Vector2((float)num * (x + 10f), 0f);
				}
			}
			TextToDisplay = template.TextToDisplay;
			SetColor(template.color);
			SetHeight(template.initialFontSize);
			tmpText.autoSizeTextContainer = true;
			tmpText.textWrappingMode = (TextWrappingModes)0;
			tmpText.alignment = (TextAlignmentOptions)((uiPosition == UIComponentPosition.TopLeft) ? 513 : 516);
			tmpText.lineSpacing = 0f;
			tmpText.fontSize = 100f;
			tmpText.outlineColor = new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue);
			tmpText.outlineWidth = 0f;
			((Graphic)tmpText).color = currColor;
			IsHidden = template?.isHidden ?? false;
		}

		public virtual bool SetColor(Color newColor)
		{
			//IL_0004: 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)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			bool result = false;
			currColor = newColor;
			if ((Object)(object)tmpText != (Object)null)
			{
				((Graphic)tmpText).color = newColor;
				result = true;
			}
			if ((Object)(object)iconImage != (Object)null)
			{
				((Graphic)iconImage).color = newColor;
				result = true;
			}
			return result;
		}

		public virtual void Update()
		{
			if (!((Object)(object)tmpText != (Object)null))
			{
				return;
			}
			string text = TextToDisplay();
			if (text != null)
			{
				tmpText.text = text;
				if (IsHidden)
				{
					IsHidden = false;
				}
			}
			else if (!IsHidden)
			{
				IsHidden = true;
			}
		}
	}
	[BepInPlugin("net.catcraze777.plugins.splitsstats", "Splits Stats", "1.4.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class SplitsStatsPlugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(GUIManager), "Start")]
		private class GUIManagerStartPatcher
		{
			private static void Postfix(GUIManager __instance)
			{
				//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_00c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cb: Expected O, but got Unknown
				try
				{
					Scene activeScene = SceneManager.GetActiveScene();
					if (!(((Scene)(ref activeScene)).name != "Airport") || !((Object)(object)__instance != (Object)null))
					{
						return;
					}
					Logger.LogInfo((object)"Starting GUIManager.Start Postfix!");
					((BaseUnityPlugin)Instance).Config.Reload();
					splitsManagerInstance = SplitsManager.CreateSplitsManager(__instance, customStats);
					foreach (BaseUIComponent customUIComponent in customUIComponents)
					{
						splitsManagerInstance.AddInfoComponentToSide(customUIComponent);
					}
					if (RunSaveManager.IsRunActive())
					{
						RunSaveManager.FinishRun();
						Logger.LogWarning((object)"Ended an active run found stored in the RunSaveManager!");
					}
					animManagerGameObject = new GameObject("SplitsStatsPlugin AnimationManager");
					animManager = animManagerGameObject.AddComponent<AnimationManager>();
					Logger.LogInfo((object)"Created AnimationManager!");
					Logger.LogInfo((object)"GUIManager.Start Postfix successfully completed!");
				}
				catch (Exception ex)
				{
					Logger.LogError((object)($"Error in GUIManager.Start patch: {ex.GetType()}" + ex.Message + $"\n{ex.Source}\n{ex.TargetSite}\n{ex.StackTrace}"));
				}
			}
		}

		[HarmonyPatch(typeof(RunManager), "StartRun")]
		private class RunManagerStartRunPatcher
		{
			private static void Postfix(RunManager __instance)
			{
				//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_00bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_0107: Unknown result type (might be due to invalid IL or missing references)
				//IL_013f: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f6: 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_014c: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_01cd: Invalid comparison between Unknown and I4
				//IL_0212: 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: Invalid comparison between Unknown and I4
				//IL_0387: Unknown result type (might be due to invalid IL or missing references)
				//IL_018a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0198: Unknown result type (might be due to invalid IL or missing references)
				//IL_019b: Invalid comparison between Unknown and I4
				//IL_0263: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
				//IL_026d: Unknown result type (might be due to invalid IL or missing references)
				//IL_027b: Unknown result type (might be due to invalid IL or missing references)
				//IL_028b: Unknown result type (might be due to invalid IL or missing references)
				//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
				//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					Scene activeScene = SceneManager.GetActiveScene();
					if (!(((Scene)(ref activeScene)).name != "Airport") || !((Object)(object)__instance != (Object)null))
					{
						return;
					}
					Logger.LogInfo((object)"Starting RunManager.StartRun Postfix!");
					if (Quicksave.ShouldUseSaveData)
					{
						RunSaveManager.ResumeQuicksave();
					}
					else
					{
						RunSaveManager.StartNewRun();
					}
					RunSaveManager.GetRunRecords(CategorizeByCurrRunConfig);
					splitsManagerInstance.SetRunTargets();
					float num = (SettingsManager.isRealTime ? GetCurrentRealTime() : Time.time);
					num += (SettingsManager.useInGameTiming ? (0f - RunManager.Instance.TimeSinceRunStarted) : Character.localCharacter.data.fallSeconds);
					Segment currentSegmentNumber = MapHandler.CurrentSegmentNumber;
					splitsManagerInstance.SetTimerHidden(currentSegmentNumber, isHidden: false);
					splitsManagerInstance.SetTimerFontSize(currentSegmentNumber, 38f);
					splitsManagerInstance.UpdateTimerPositions();
					if (splitsManagerInstance.StartTimerAtTime(currentSegmentNumber, num))
					{
						Logger.LogInfo((object)$"Started {currentSegmentNumber} timer!");
					}
					if (Quicksave.ShouldUseSaveData)
					{
						Logger.LogInfo((object)"Resuming quicksave, attempting to load previous saved run into timers...");
						float num2 = 0f;
						Segment val = (Segment)0;
						while (val < currentSegmentNumber)
						{
							float num3 = RunSaveManager.currentRun[val];
							if (num3 > 0f)
							{
								num2 += num3;
								if (SettingsManager.sharedBiomeIcons && (int)val != 6)
								{
									splitsManagerInstance.UpdateTimerIcon(val, false);
									if ((int)val == 3)
									{
										splitsManagerInstance.UpdateTimerIcon((Segment)4, false);
									}
								}
								val = (Segment)(byte)(val + 1);
								continue;
							}
							Logger.LogError((object)"Valid previous run not found! Using fresh times instead!");
							if ((int)val > 0)
							{
								Logger.LogInfo((object)"For some reason the current run had at least one previous segment time valid for the quicksave, please debug RunTime.ResumeLastRun() this shouldn't be possible!");
							}
							num2 = -1f;
							break;
						}
						if (num2 > 0f && RunSaveManager.currentRun[currentSegmentNumber] > 0f)
						{
							Logger.LogError((object)"For some reason the current run had all previous segments valid for the quicksave except the current starting segment, please debug RunTime.ResumeLastRun() this shouldn't be possible!");
							num2 = -1f;
						}
						if (num2 > 0f)
						{
							num = (TimerComponent.runStartTime = num - num2);
							float num4 = num;
							for (Segment val2 = (Segment)0; val2 < currentSegmentNumber; val2 = (Segment)(byte)(val2 + 1))
							{
								float num5 = RunSaveManager.currentRun[val2];
								if (!splitsManagerInstance.StartTimerAtTime(val2, num4) || !splitsManagerInstance.EndTimerAtTime(val2, num4 + num5))
								{
									Logger.LogWarning((object)$"{val2} segment time found, but unable to load into segment timer!");
								}
								num4 += num5;
							}
							Logger.LogInfo((object)"Successfully loaded previous saved run!");
						}
					}
					splitsManagerInstance.mainTimer.SetPaceTextActive(SettingsManager.showRunPace && SettingsManager.paceTextEnabled);
					splitsManagerInstance.mainTimer.StartRunAtTime(num);
					splitsManagerInstance.mainTimer.SetHeight(50f);
					if (RunSaveManager.currentRun.ascentDifficulty >= 8 && !SettingsManager.hiddenSegments)
					{
						Logger.LogInfo((object)"Ascent is 8 or higher, displaying Nadir timer...");
						if (!splitsManagerInstance.SetTimerHidden((Segment)6, isHidden: false))
						{
							Logger.LogError((object)"Could not display nadir timer!");
						}
					}
					SplitsManager.FindFlagPole();
					Logger.LogInfo((object)"RunManager.StartRun Postfix successfully completed!");
				}
				catch (Exception ex)
				{
					Logger.LogError((object)($"Error in RunManager.StartRun patch: {ex.GetType()}" + ex.Message + $"\n{ex.Source}\n{ex.TargetSite}\n{ex.StackTrace}"));
				}
			}
		}

		[HarmonyPatch(typeof(AscentUI), "Start")]
		private class AscentUIPatcher
		{
			private static void Postfix(AscentUI __instance)
			{
				try
				{
					if (!SettingsManager.showCurrentCategory || !SettingsManager.isCategorized)
					{
						return;
					}
					Logger.LogInfo((object)"Starting AscentUI.Start Postfix!");
					((Component)__instance).gameObject.SetActive(true);
					if (SettingsManager.categorizeByPlayerCount)
					{
						TextMeshProUGUI text = __instance.text;
						((TMP_Text)text).text = ((TMP_Text)text).text + $"   {RunSaveManager.currentRun.playerCount} SCOUT";
						if (RunSaveManager.currentRun.playerCount > 1)
						{
							TextMeshProUGUI text2 = __instance.text;
							((TMP_Text)text2).text = ((TMP_Text)text2).text + "S";
						}
						Logger.LogInfo((object)"Added player count category text!");
					}
					if (SettingsManager.categorizeByLevel)
					{
						if (RunSaveManager.currentRun.wasRandomized)
						{
							if (!TerrainRandomiserInteractor.autoRandomise() && SettingsManager.categorizeBySeed)
							{
								TextMeshProUGUI text3 = __instance.text;
								((TMP_Text)text3).text = ((TMP_Text)text3).text + "   SEEDED";
							}
							else
							{
								TextMeshProUGUI text4 = __instance.text;
								((TMP_Text)text4).text = ((TMP_Text)text4).text + "   RANDOM";
							}
						}
						else
						{
							TextMeshProUGUI text5 = __instance.text;
							((TMP_Text)text5).text = ((TMP_Text)text5).text + "   " + RunSaveManager.currentRun.levelName.Replace("Level_", "DAILY #");
						}
						Logger.LogInfo((object)"Added level category text!");
					}
					else if (RunSaveManager.currentRun.wasRandomized && SettingsManager.categorizeByTerrainRandomizer)
					{
						if (!TerrainRandomiserInteractor.autoRandomise() && SettingsManager.categorizeBySeed)
						{
							TextMeshProUGUI text6 = __instance.text;
							((TMP_Text)text6).text = ((TMP_Text)text6).text + "   SEEDED";
						}
						else
						{
							TextMeshProUGUI text7 = __instance.text;
							((TMP_Text)text7).text = ((TMP_Text)text7).text + "   RANDOM";
						}
						Logger.LogInfo((object)"Added randomizer category text!");
					}
					Logger.LogInfo((object)"AscentUI.Start Postfix successfully completed!");
				}
				catch (Exception ex)
				{
					Logger.LogError((object)($"Error in AscentUI.Start patch: {ex.GetType()}" + ex.Message + $"\n{ex.Source}\n{ex.TargetSite}\n{ex.StackTrace}"));
				}
			}
		}

		[HarmonyPatch(typeof(MapHandler), "GoToSegment")]
		private class MapHandlerGoToSegmentPatcher
		{
			private static void Postfix(MapHandler __instance, ref Segment s)
			{
				try
				{
					Logger.LogInfo((object)"Starting MapHandler.GoToSegment Postfix!");
					TransitionToSegment(s);
					Logger.LogInfo((object)"MapHandler.GoToSegment Postfix successfully completed!");
				}
				catch (Exception ex)
				{
					Logger.LogError((object)($"Error in MapHandler.GoToSegment patch: {ex.GetType()}" + ex.Message + $"\n{ex.Source}\n{ex.TargetSite}\n{ex.StackTrace}"));
				}
			}
		}

		[HarmonyPatch(typeof(MapHandler), "JumpToSegment")]
		private class MapHandlerJumpToSegmentPatcher
		{
			private static void Postfix(MapHandler __instance, ref Segment segment)
			{
				//IL_0037: 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_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: 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_009e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					Logger.LogInfo((object)"Starting MapHandler.JumpToSegment Postfix!");
					TransitionToSegment(segment);
					Segment[] array = new Segment[5];
					RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
					Segment[] array2 = (Segment[])(object)array;
					foreach (Segment val in array2)
					{
						if (splitsManagerInstance.splitTimers.ContainsKey(val) && splitsManagerInstance.splitTimers[val].timerOn)
						{
							splitsManagerInstance.EndTimer(val);
							animManager.LerpTimerFontSize(splitsManagerInstance.splitTimers[val], 30f, 0.4f);
							RunSaveManager.currentRun[val] = splitsManagerInstance.splitTimers[val].totalTime;
							RunSaveManager.SaveRun();
							Logger.LogInfo((object)$"Stopped {val} timer!");
						}
					}
					Logger.LogInfo((object)"MapHandler.JumpToSegment Postfix successfully completed!");
				}
				catch (Exception ex)
				{
					Logger.LogError((object)($"Error in MapHandler.JumpToSegment patch: {ex.GetType()}" + ex.Message + $"\n{ex.Source}\n{ex.TargetSite}\n{ex.StackTrace}"));
				}
			}
		}

		[HarmonyPatch(typeof(RunManager), "EndGame")]
		private class RunManagerPatcher
		{
			private static void Postfix(RunManager __instance)
			{
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: 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)
				//IL_006e: Invalid comparison between Unknown and I4
				//IL_0083: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
				//IL_0114: Unknown result type (might be due to invalid IL or missing references)
				//IL_012c: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					Logger.LogInfo((object)"Starting RunManager.EndGame Postfix!");
					splitsManagerInstance.mainTimer.EndTimer();
					if (!SettingsManager.segmentTimersEnabled)
					{
						Logger.LogInfo((object)"Segment timers disabled, RunManager.EndGame Postfix successfully completed!");
						return;
					}
					foreach (Segment value in Enum.GetValues(typeof(Segment)))
					{
						if ((int)value != 5 && splitsManagerInstance.splitTimers.ContainsKey(value))
						{
							Logger.LogInfo((object)$"Stopping {(object)value} timer...");
							TimerComponent timerComponent = splitsManagerInstance.splitTimers[value];
							bool paceTextActive = timerComponent.GetPaceTextActive();
							timerComponent.EndTimer();
							timerComponent.SetPaceTextActive(paceTextActive);
							timerComponent.SetCurrColor(timerComponent.inactiveColor);
							animManager.LerpTimerFontSize(splitsManagerInstance.splitTimers[value], 30f, 0.4f);
							RunSaveManager.currentRun[value] = timerComponent.totalTime;
							Logger.LogInfo((object)$"Successfully stopped {(object)value} timer!");
						}
					}
					splitsManagerInstance.UpdateTimerPositions();
					RunSaveManager.SaveRun();
					Logger.LogInfo((object)"RunManager.EndGame Postfix successfully completed!");
				}
				catch (Exception ex)
				{
					Logger.LogError((object)($"Error in RunManager.EndGame patch: {ex.GetType()}" + ex.Message + $"\n{ex.Source}\n{ex.TargetSite}\n{ex.StackTrace}"));
				}
			}
		}

		[HarmonyPatch(typeof(MountainProgressHandler), "TriggerReached")]
		private class MountainProgressHandlerPatcher
		{
			private static void Postfix(EndScreen __instance, ProgressPoint progressPoint)
			{
				try
				{
					if (progressPoint.title == "PEAK")
					{
						Logger.LogInfo((object)"Starting MountainProgressHandler.TriggerReached postfix!");
						if (SettingsManager.showPaceNearGoals && SettingsManager.paceTextEnabled)
						{
							Logger.LogInfo((object)"Peak reached, showing main timer pace text");
							splitsManagerInstance.mainTimer.SetPaceTextActive(isActive: true);
						}
						Logger.LogInfo((object)"MountainProgressHandler.TriggerReached Postfix successfully completed!");
					}
				}
				catch (Exception ex)
				{
					Logger.LogError((object)($"Error in MountainProgressHandler.TriggerReached patch: {ex.GetType()}" + ex.Message + $"\n{ex.Source}\n{ex.TargetSite}\n{ex.StackTrace}"));
				}
			}
		}

		[HarmonyPatch(typeof(EndScreen), "GetTimeString")]
		private class EndScreenPatcher
		{
			private static void Postfix(EndScreen __instance, ref string __result, float totalSeconds)
			{
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_009c: Invalid comparison between Unknown and I4
				//IL_0224: Unknown result type (might be due to invalid IL or missing references)
				//IL_022e: Unknown result type (might be due to invalid IL or missing references)
				//IL_023b: Unknown result type (might be due to invalid IL or missing references)
				//IL_024f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0259: 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_00d4: Invalid comparison between Unknown and I4
				//IL_011c: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
				//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
				//IL_0302: Unknown result type (might be due to invalid IL or missing references)
				//IL_0311: 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_03f0: 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_0404: Unknown result type (might be due to invalid IL or missing references)
				//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
				//IL_03e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_03d2: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					Logger.LogInfo((object)"Starting EndScreen.GetTimeString postfix!");
					bool flag = Character.localCharacter.refs.stats.won || Character.localCharacter.refs.stats.somebodyElseWon;
					if (RunSaveManager.IsRunActive())
					{
						Logger.LogInfo((object)"Writing final time of completed run...");
						float num = ((SettingsManager.isRealTime || !SettingsManager.useInGameTiming) ? splitsManagerInstance.mainTimer.totalTime : totalSeconds);
						RunSaveManager.currentRun.finalTime = num;
						if (RunSettings.isMiniRun)
						{
							if ((int)MapHandler.CurrentSegmentNumber >= 6)
							{
								RunSaveManager.currentRun[(Segment)6] = num - RunSaveManager.currentRun[(Segment)4] - RunSaveManager.currentRun[(Segment)3];
							}
							else if ((int)MapHandler.CurrentSegmentNumber >= 4)
							{
								RunSaveManager.currentRun[(Segment)4] = num - RunSaveManager.currentRun[(Segment)3];
							}
							else
							{
								RunSaveManager.currentRun[(Segment)(byte)RunSettings.GetValue((SETTINGTYPE)10050, false)] = num;
							}
							Logger.LogInfo((object)$"Writing segment time(s) of minirun after ending in segment {MapHandler.CurrentSegmentNumber}...");
						}
						RunSaveManager.currentRun.runFinished = flag;
					}
					RunSaveManager.FinishRun();
					Logger.LogInfo((object)"Run finished...");
					if (SettingsManager.canEditEndScreenTime)
					{
						Logger.LogInfo((object)"Editting end screen...");
						__result = __result + "." + $"{Mathf.FloorToInt((float)SettingsManager.precisionInTimer * (totalSeconds % 1f))}".PadLeft(SettingsManager.precisionInTimer, '0');
						if (SettingsManager.isRealTime || !SettingsManager.useInGameTiming)
						{
							__result = TimerComponent.GetTimeString(splitsManagerInstance.mainTimer.totalTime, showHour: true, showMinute: true, SettingsManager.precisionInTimer);
						}
						__instance.endTime.fontSizeMax = __instance.endTime.fontSize;
						__instance.endTime.enableAutoSizing = true;
						RectTransform component = ((Component)__instance.endTime).gameObject.GetComponent<RectTransform>();
						component.sizeDelta = new Vector2(-22f, component.sizeDelta.y);
						component.pivot = Vector2.one;
						component.anchoredPosition = new Vector2(-9f, component.anchoredPosition.y);
						Logger.LogInfo((object)"Editted time string text and object!");
						float? currPace = splitsManagerInstance.mainTimer.currPace;
						if (flag && SettingsManager.paceTextEnabled && currPace.HasValue && (!SettingsManager.onlyShowFinalRunPaceIfRecord || currPace.Value <= 0f))
						{
							float num2 = currPace.Value;
							Logger.LogInfo((object)"Adding pace text to end screen...");
							RectTransform val = Object.Instantiate<RectTransform>(component, ((Transform)component).parent);
							val.sizeDelta += new Vector2(-40f, 0f);
							val.anchoredPosition = new Vector2(val.anchoredPosition.x, 0f);
							((Component)val).gameObject.SetActive(true);
							TMP_Text component2 = ((Component)val).GetComponent<TMP_Text>();
							component2.fontSizeMax = 18f;
							component2.text = TimerComponent.GetTimeString(num2, showHour: false, showMinute: false, (SettingsManager.precisionInTimer > 0) ? 1 : 0, showPositiveSign: true);
							if (SettingsManager.useColorPace)
							{
								float recordTime = splitsManagerInstance.mainTimer.recordTime;
								if (recordTime > 0f && splitsManagerInstance.mainTimer.currTime < recordTime)
								{
									((Graphic)component2).color = TimerComponent.goldSplitColor;
								}
								else if (num2 <= 0f)
								{
									((Graphic)component2).color = TimerComponent.greenSplitColor;
								}
								else
								{
									((Graphic)component2).color = TimerComponent.redSplitColor;
								}
							}
							component.anchoredPosition += new Vector2(0f, -2f);
							Logger.LogInfo((object)"Pace text added!");
						}
					}
					Logger.LogInfo((object)"EndScreen.GetTimeString Postfix successfully completed!");
				}
				catch (Exception ex)
				{
					Logger.LogError((object)($"Error in EndScreen.GetTimeString patch: {ex.GetType()}" + ex.Message + $"\n{ex.Source}\n{ex.TargetSite}\n{ex.StackTrace}"));
				}
			}
		}

		[HarmonyPatch(typeof(Quicksave), "SaveNow")]
		private class QuicksavePatcher
		{
			private static void Postfix()
			{
				try
				{
					if (RunSaveManager.IsRunActive())
					{
						Logger.LogInfo((object)"Starting Quicksave.SaveNow postfix!");
						RunSaveManager.TryWriteQuickSave();
						Logger.LogInfo((object)"Quicksave.SaveNow Postfix successfully completed!");
					}
				}
				catch (Exception ex)
				{
					Logger.LogError((object)($"Error in Quicksave.SaveNow patch: {ex.GetType()}" + ex.Message + $"\n{ex.Source}\n{ex.TargetSite}\n{ex.StackTrace}"));
				}
			}
		}

		public static SplitsStatsPlugin Instance;

		internal static ManualLogSource Logger;

		private static Harmony _harmony;

		public const string PLUGIN_GUID = "net.catcraze777.plugins.splitsstats";

		private static SplitsManager splitsManagerInstance;

		private static GameObject animManagerGameObject;

		private static AnimationManager animManager;

		private static bool _hasTerrainRandomiser = false;

		private const float FONT_CHANGE_DURATION = 0.4f;

		private const bool alwaysSave = true;

		internal static List<InfoComponentTemplate> customStats = new List<InfoComponentTemplate>();

		internal static List<BaseUIComponent> customUIComponents = new List<BaseUIComponent>();

		private static DateTime REFERENCE_REAL_TIME = DateTime.UtcNow;

		public static bool hasTerrainRandomiser
		{
			get
			{
				return _hasTerrainRandomiser;
			}
			private set
			{
				_hasTerrainRandomiser = value;
			}
		}

		public static void AddCustomStat(InfoComponentTemplate addonTemplate)
		{
			customStats.Add(addonTemplate);
		}

		public static void AddCustomComponent(BaseUIComponent newComponent)
		{
			customUIComponents.Add(newComponent);
		}

		public static Sprite LoadSprite(string relativeImgPath)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_004a: 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)
			try
			{
				string directoryName = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
				string path = Path.Combine(directoryName, relativeImgPath);
				byte[] array = File.ReadAllBytes(path);
				Texture2D val = new Texture2D(1, 1);
				ImageConversion.LoadImage(val, array);
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			}
			catch
			{
				return null;
			}
		}

		public static bool CategorizeByCurrRunConfig(RunTime otherRunTime)
		{
			RunTime currentRun = RunSaveManager.currentRun;
			if (currentRun == null)
			{
				return true;
			}
			if (currentRun.isRealTime != otherRunTime.isRealTime)
			{
				return false;
			}
			if ((SettingsManager.categorizeByGameVersion || SettingsManager.categorizeByLevel) && currentRun.gameVersion != otherRunTime.gameVersion)
			{
				return false;
			}
			if (SettingsManager.categorizeByPlayerCount && currentRun.playerCount != otherRunTime.playerCount)
			{
				return false;
			}
			if (SettingsManager.categorizeByAscent && currentRun.ascentDifficulty != otherRunTime.ascentDifficulty)
			{
				return false;
			}
			if ((SettingsManager.categorizeByLevel && currentRun.levelName != otherRunTime.levelName) || currentRun.wasRandomized != otherRunTime.wasRandomized)
			{
				return false;
			}
			if ((SettingsManager.categorizeByTerrainRandomizer || SettingsManager.categorizeByLevel) && currentRun.wasRandomized != otherRunTime.wasRandomized)
			{
				return false;
			}
			if (SettingsManager.categorizeBySeed && currentRun.seed != otherRunTime.seed)
			{
				return false;
			}
			if (SettingsManager.categorizeByCustomRun && !SettingsManager.customRunNormalPace && (currentRun.customRun != otherRunTime.customRun || currentRun.customRunSettingsHash != otherRunTime.customRunSettingsHash))
			{
				return false;
			}
			if (SettingsManager.customRunNormalPace && otherRunTime.customRun)
			{
				return false;
			}
			return true;
		}

		public static float GetCurrentRealTime()
		{
			return (float)(DateTime.UtcNow - REFERENCE_REAL_TIME).TotalSeconds;
		}

		private static void TransitionToSegment(Segment s)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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_01c3: Invalid comparison between Unknown and I4
			//IL_012c: 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_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Invalid comparison between Unknown and I4
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Invalid comparison between Unknown and I4
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Invalid comparison between Unknown and I4
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Invalid comparison between Unknown and I4
			Logger.LogInfo((object)$"Split reached, entering {s}!");
			if (splitsManagerInstance.splitTimers.ContainsKey(s))
			{
				if (SettingsManager.hiddenSegments || (int)s == 6)
				{
					splitsManagerInstance.splitTimers[s].IsHidden = false;
					splitsManagerInstance.splitTimers[s].SetHeight(0f);
				}
				if (SettingsManager.sharedBiomeIcons && (int)s != 6)
				{
					splitsManagerInstance.UpdateTimerIcon(s, false);
					if ((int)s == 3)
					{
						splitsManagerInstance.UpdateTimerIcon((Segment)4, false);
					}
				}
				animManager.LerpTimerFontSize(splitsManagerInstance.splitTimers[s], 38f, 0.4f);
				splitsManagerInstance.StartTimer(s);
				Logger.LogInfo((object)$"Started {s} timer!");
			}
			if (splitsManagerInstance.splitTimers.ContainsKey((Segment)(byte)(s - 1)))
			{
				splitsManagerInstance.EndTimer((Segment)(byte)(s - 1));
				animManager.LerpTimerFontSize(splitsManagerInstance.splitTimers[(Segment)(byte)(s - 1)], 30f, 0.4f);
				if (RunSaveManager.IsRunActive())
				{
					RunSaveManager.currentRun[(Segment)(byte)(s - 1)] = splitsManagerInstance.splitTimers[(Segment)(byte)(s - 1)].totalTime;
					RunSaveManager.SaveRun();
				}
				Logger.LogInfo((object)$"Stopped {(object)(Segment)(byte)(s - 1)} timer!");
			}
			if ((int)s == 4)
			{
				if (RunSettings.isMiniRun && RunSaveManager.IsRunActive())
				{
					RunSaveManager.currentRun[(Segment)3] = splitsManagerInstance.mainTimer.currTime;
					RunSaveManager.SaveRun();
					Logger.LogInfo((object)"Saved caldera/gloom time for minirun!");
				}
				Sprite val = LoadSprite("img_peak.png");
				if ((Object)(object)val != (Object)null)
				{
					splitsManagerInstance.ChangeCampfireIcon(val);
				}
				Logger.LogInfo((object)"Updated campfire icon to flag!");
			}
			else if ((int)s == 6)
			{
				if (RunSettings.isMiniRun && RunSaveManager.IsRunActive())
				{
					RunSaveManager.currentRun[(Segment)4] = splitsManagerInstance.mainTimer.currTime - RunSaveManager.currentRun[(Segment)3];
					RunSaveManager.SaveRun();
					Logger.LogInfo((object)"Saved caldera/gloom time for minirun!");
				}
				Sprite val2 = LoadSprite("img_peak_gate.png");
				if ((Object)(object)val2 != (Object)null)
				{
					splitsManagerInstance.ChangeCampfireIcon(val2);
				}
				Logger.LogInfo((object)"Updated campfire icon to peak gate!");
			}
			splitsManagerInstance.UpdateTimerPositions();
		}

		private void Awake()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"Plugin net.catcraze777.plugins.splitsstats is loaded!");
			SettingsManager.InitSettingsManager(((BaseUnityPlugin)this).Config);
			SettingsManager.LoadConfigBindings();
			RunSaveManager.InitRunSaveManager();
			hasTerrainRandomiser = Chainloader.PluginInfos.ContainsKey("com.snosz.terrainrandomiser");
			_harmony = new Harmony("net.catcraze777.plugins.splitsstats");
			_harmony.PatchAll();
		}
	}
	public class TerrainRandomiserInteractor
	{
		private static MapSettings CurrSettings
		{
			get
			{
				if (!SplitsStatsPlugin.hasTerrainRandomiser)
				{
					return null;
				}
				if (PhotonNetwork.IsMasterClient)
				{
					return Plugin.Instance?.mapSettings;
				}
				return Plugin.Instance?.roomMapSettings;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static bool shouldRandomise()
		{
			if (SplitsStatsPlugin.hasTerrainRandomiser)
			{
				return CurrSettings?.enableRandomiser ?? false;
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static bool autoRandomise()
		{
			if (SplitsStatsPlugin.hasTerrainRandomiser)
			{
				return CurrSettings?.autoRandomSeed ?? false;
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static int masterSeed()
		{
			if (SplitsStatsPlugin.hasTerrainRandomiser)
			{
				return CurrSettings?.seed ?? (-1);
			}
			return -1;
		}
	}
	public class RunSaveManager
	{
		public static Func<RunTime, bool> CategorizationFunc = null;

		public static readonly Func<RunTime, bool> IncludeAllRuns = (RunTime _) => true;

		private static List<RunTime> runStorage;

		private static string jsonDirectory;

		private static string jsonFilePath;

		private static string quicksaveFilePath;

		private const string saveFileName = "savedRuns.json";

		private const string quicksaveFileName = "quickSave.json";

		public static RunTime targetRun
		{
			get
			{
				if (SettingsManager.useAverageRun)
				{
					return averageRun;
				}
				return fastestRun;
			}
		}

		public static float targetShore
		{
			get
			{
				if (SettingsManager.useAverageRun)
				{
					return averageShore;
				}
				return fastestShore;
			}
		}

		public static float targetTropics
		{
			get
			{
				if (SettingsManager.useAverageRun)
				{
					return averageTropics;
				}
				return fastestTropics;
			}
		}

		public static float targetAlpmesa
		{
			get
			{
				if (SettingsManager.useAverageRun)
				{
					return averageAlpmesa;
				}
				return fastestAlpmesa;
			}
		}

		public static float targetCaldera
		{
			get
			{
				if (SettingsManager.useAverageRun)
				{
					return averageCaldera;
				}
				return fastestCaldera;
			}
		}

		public static float targetKiln
		{
			get
			{
				if (SettingsManager.useAverageRun)
				{
					return averageKiln;
				}
				return fastestKiln;
			}
		}

		public static float targetNadir
		{
			get
			{
				if (SettingsManager.useAverageRun)
				{
					return averageNadir;
				}
				return fastestNadir;
			}
		}

		public static float targetBiome4
		{
			get
			{
				if (SettingsManager.useAverageRun)
				{
					return averageBiome4;
				}
				return fastestBiome4;
			}
		}

		public static RunTime fastestRun { get; private set; }

		public static float fastestShore { get; private set; }

		public static float fastestTropics { get; private set; }

		public static float fastestAlpmesa { get; private set; }

		public static float fastestCaldera { get; private set; }

		public static float fastestKiln { get; private set; }

		public static float fastestNadir { get; private set; }

		public static float fastestBiome4 { get; private set; }

		public static RunTime averageRun { get; private set; }

		public static float averageShore { get; private set; }

		public static float averageTropics { get; private set; }

		public static float averageAlpmesa { get; private set; }

		public static float averageCaldera { get; private set; }

		public static float averageKiln { get; private set; }

		public static float averageNadir { get; private set; }

		public static float averageBiome4 { get; private set; }

		public static int totalAttempts { get; private set; }

		public static float SumOfBest
		{
			get
			{
				if ((double)fastestShore < 0.0)
				{
					return -1f;
				}
				if ((double)fastestTropics < 0.0)
				{
					return -1f;
				}
				if ((double)fastestAlpmesa < 0.0)
				{
					return -1f;
				}
				if ((double)fastestCaldera < 0.0)
				{
					return -1f;
				}
				if ((double)fastestKiln < 0.0)
				{
					return -1f;
				}
				bool flag = targetRun != null && targetRun.ascentDifficulty >= 8;
				if (flag && (double)fastestNadir < 0.0)
				{
					return -1f;
				}
				return fastestShore + fastestTropics + fastestAlpmesa + fastestCaldera + fastestKiln + (flag ? fastestNadir : 0f);
			}
		}

		public static RunTime currentRun { get; private set; }

		public static float targetSegment(Segment indexSegment)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if (SettingsManager.useAverageRun)
			{
				return averageSegment(indexSegment);
			}
			return fastestSegment(indexSegment);
		}

		public static float fastestSegment(Segment indexSegment)
		{
			//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_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: 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)
			//IL_0027: Expected I4, but got Unknown
			return (int)indexSegment switch
			{
				0 => fastestShore, 
				1 => fastestTropics, 
				2 => fastestAlpmesa, 
				3 => fastestCaldera, 
				4 => fastestKiln, 
				6 => fastestNadir, 
				_ => throw new IndexOutOfRangeException(), 
			};
		}

		public static float averageSegment(Segment indexSegment)
		{
			//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_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: 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)
			//IL_0027: Expected I4, but got Unknown
			return (int)indexSegment switch
			{
				0 => averageShore, 
				1 => averageTropics, 
				2 => averageAlpmesa, 
				3 => averageCaldera, 
				4 => averageKiln, 
				6 => averageNadir, 
				_ => throw new IndexOutOfRangeException(), 
			};
		}

		public static void InitRunSaveManager()
		{
			if (SplitsStatsPlugin.Logger != null)
			{
				SplitsStatsPlugin.Logger.LogInfo((object)"Initializing Run Save Manager...");
			}
			if (jsonFilePath == null)
			{
				GetFilePaths();
			}
			try
			{
				TryReadSave();
			}
			catch (Exception ex)
			{
				if (SplitsStatsPlugin.Logger != null)
				{
					SplitsStatsPlugin.Logger.LogError((object)$"Unable to read saved runs! An error occured: {ex.GetType()} {ex.Message}");
				}
				runStorage = new List<RunTime>();
			}
			GetRunRecords();
		}

		public static RunTime StartNewRun()
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			if (IsRunActive())
			{
				if (SplitsStatsPlugin.Logger != null)
				{
					SplitsStatsPlugin.Logger.LogError((object)"Tried to start a run when one is already started!");
				}
				return null;
			}
			SplitsStatsPlugin.Logger.LogInfo((object)"Starting new run...");
			currentRun = new RunTime();
			currentRun.UpdateTimeString();
			runStorage.Add(new RunTime(currentRun));
			currentRun.playerCount = PhotonNetwork.PlayerList.Length;
			RunTime runTime = currentRun;
			Scene activeScene = SceneManager.GetActiveScene();
			runTime.levelName = ((Scene)(ref activeScene)).name;
			currentRun.gameVersion = "v" + Application.version;
			currentRun.ascentDifficulty = Ascents.currentAscent;
			currentRun.isRealTime = SettingsManager.isRealTime;
			if (RunSettings.IsCustomRun)
			{
				currentRun.customRun = true;
				uint num = 2166136261u;
				foreach (SETTINGTYPE value in Enum.GetValues(typeof(SETTINGTYPE)))
				{
					num ^= (uint)RunSettings.GetValue(value, false);
					num *= 16777619;
				}
				currentRun.customRunSettingsHash = num;
			}
			else
			{
				currentRun.customRun = false;
			}
			if (SplitsStatsPlugin.hasTerrainRandomiser)
			{
				currentRun.wasRandomized = TerrainRandomiserInteractor.shouldRandomise();
				currentRun.seed = TerrainRandomiserInteractor.masterSeed();
			}
			SplitsStatsPlugin.Logger.LogInfo((object)"Loaded run information!");
			return currentRun;
		}

		public static RunTime ResumeQuicksave()
		{
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			if (!Quicksave.ShouldUseSaveData)
			{
				if (SplitsStatsPlugin.Logger != null)
				{
					SplitsStatsPlugin.Logger.LogError((object)"Tried to resume a run when we aren't resuming from a save!");
				}
				return null;
			}
			if (IsRunActive())
			{
				if (SplitsStatsPlugin.Logger != null)
				{
					SplitsStatsPlugin.Logger.LogError((object)"Tried to resume a run when one is already started!");
				}
				return null;
			}
			StartNewRun();
			if (runStorage.Count <= 1)
			{
				if (SplitsStatsPlugin.Logger != null)
				{
					SplitsStatsPlugin.Logger.LogError((object)"Tried to resume a run when there is no run to load!");
				}
				return null;
			}
			SplitsStatsPlugin.Logger.LogInfo((object)"Attempting to resume last run...");
			RunTime runTime;
			try
			{
				runTime = TryReadQuickSave();
			}
			catch (Exception ex)
			{
				if (SplitsStatsPlugin.Logger != null)
				{
					SplitsStatsPlugin.Logger.LogError((object)$"Unable to read quicksave! An error occured: {ex.GetType()} {ex.Message}");
				}
				return null;
			}
			bool flag = true;
			if (currentRun.runFinished != runTime.runFinished)
			{
				flag = false;
			}
			if (currentRun.gameVersion != runTime.gameVersion)
			{
				flag = false;
			}
			if (currentRun.levelName != runTime.levelName)
			{
				flag = false;
			}
			if (currentRun.ascentDifficulty != runTime.ascentDifficulty)
			{
				flag = false;
			}
			if (currentRun.customRun != runTime.customRun)
			{
				flag = false;
			}
			if (currentRun.customRun && runTime.customRun && currentRun.customRunSettingsHash != runTime.customRunSettingsHash)
			{
				flag = false;
			}
			if (currentRun.wasRandomized != runTime.wasRandomized)
			{
				flag = false;
			}
			if (currentRun.wasRandomized && runTime.wasRandomized && currentRun.seed != runTime.seed)
			{
				flag = false;
			}
			if (SettingsManager.categorizeByPlayerCount && currentRun.playerCount != runTime.playerCount)
			{
				flag = false;
			}
			if (!flag)
			{
				if (SplitsStatsPlugin.Logger != null)
				{
					SplitsStatsPlugin.Logger.LogError((object)"Previous run has different run settings, unable to resume run!");
				}
				return null;
			}
			for (Segment val = (Segment)0; val < MapHandler.CurrentSegmentNumber; val = (Segment)(byte)(val + 1))
			{
				if (runTime[val] <= 0f)
				{
					if (SplitsStatsPlugin.Logger != null)
					{
						SplitsStatsPlugin.Logger.LogError((object)"Previous run has a missing segment time, unable to resume run!");
					}
					return null;
				}
			}
			if (runTime[MapHandler.CurrentSegmentNumber] > 0f)
			{
				if (SplitsStatsPlugin.Logger != null)
				{
					SplitsStatsPlugin.Logger.LogError((object)$"Previous run has a time already saved for the current segment {MapHandler.CurrentSegmentNumber}, unable to resume run!");
				}
				return null;
			}
			for (int num = runStorage.Count - 1; num >= 0; num--)
			{
				if (runStorage[num].Equals(runTime) && runStorage[num].runDate == runTime.runDate)
				{
					if (SplitsStatsPlugin.Logger != null)
					{
						SplitsStatsPlugin.Logger.LogInfo((object)"Found quicksaved run in storage, deleting it!");
					}
					runStorage.RemoveAt(num);
					break;
				}
				if (DateTime.TryParseExact(runTime.runDate, "g", CultureInfo.CurrentCulture, DateTimeStyles.None, out var result) && DateTime.TryParseExact(runStorage[num].runDate, "g", CultureInfo.CurrentCulture, DateTimeStyles.None, out var result2) && result > result2)
				{
					break;
				}
			}
			SplitsStatsPlugin.Logger.LogInfo((object)"Last run successfully resumed!");
			currentRun = runTime;
			SaveRun();
			return currentRun;
		}

		public static bool SaveRun(bool? forceSave = null)
		{
			bool flag = forceSave ?? SettingsManager.saveEmptyRuns;
			if (!IsRunActive())
			{
				if (SplitsStatsPlugin.Logger != null)
				{
					SplitsStatsPlugin.Logger.LogError((object)"Tried to save a run when no run has been started!");
				}
				return false;
			}
			List<RunTime> list = runStorage;
			list[list.Count - 1] = new RunTime(currentRun);
			try
			{
				if (currentRun.HasTimes() || flag)
				{
					TryWriteSave();
				}
				return true;
			}
			catch (Exception ex)
			{
				if (SplitsStatsPlugin.Logger != null)
				{
					SplitsStatsPlugin.Logger.LogError((object)$"Unable to save run! An error occured: {ex.GetType()} {ex.Message}");
				}
				return false;
			}
		}

		public static bool FinishRun()
		{
			bool flag = SaveRun();
			ClearInternalSavedRuns();
			if (flag)
			{
				currentRun = null;
				return true;
			}
			return false;
		}

		public static bool IsRunActive()
		{
			return currentRun != null;
		}

		public static bool IsRunValid()
		{
			if (RunSettings.IsCustomRun)
			{
				return false;
			}
			if (Quicksave.ShouldUseSaveData)
			{
				return false;
			}
			return true;
		}

		private static void GetFilePaths()
		{
			jsonDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			jsonFilePath = Path.Combine(jsonDirectory, "savedRuns.json");
			quicksaveFilePath = Path.Combine(jsonDirectory, "quickSave.json");
		}

		public static void TryReadSave()
		{
			if (!File.Exists(jsonFilePath))
			{
				throw new FileNotFoundException("Could not find file savedRuns.json to load data from!");
			}
			string text = File.ReadAllText(jsonFilePath);
			runStorage = JsonConvert.DeserializeObject<List<RunTime>>(text);
			if (SplitsStatsPlugin.Logger != null)
			{
				SplitsStatsPlugin.Logger.LogInfo((object)"Successfully read saved runs!");
			}
		}

		public static void TryWriteSave()
		{
			string contents = JsonConvert.SerializeObject((object)runStorage, (Formatting)1);
			File.WriteAllText(jsonFilePath, contents);
			if (SplitsStatsPlugin.Logger != null)
			{
				SplitsStatsPlugin.Logger.LogInfo((object)"Successfully wrote saved runs!");
			}
		}

		public static RunTime TryReadQuickSave()
		{
			if (!File.Exists(quicksaveFilePath))
			{
				throw new FileNotFoundException("Could not find file quickSave.json to load data from!");
			}
			string text = File.ReadAllText(quicksaveFilePath);
			RunTime result = JsonConvert.DeserializeObject<RunTime>(text);
			if (SplitsStatsPlugin.Logger != null)
			{
				SplitsStatsPlugin.Logger.LogInfo((object)"Successfully read quicksave!");
			}
			return result;
		}

		public static void TryWriteQuickSave()
		{
			if (!IsRunActive())
			{
				throw new NullReferenceException("No run currently active to quicksave!");
			}
			string contents = JsonConvert.SerializeObject((object)currentRun, (Formatting)1);
			File.WriteAllText(quicksaveFilePath, contents);
			if (SplitsStatsPlugin.Logger != null)
			{
				SplitsStatsPlugin.Logger.LogInfo((object)"Successfully wrote quicksave!");
			}
		}

		private static void ClearInternalSavedRuns()
		{
			fastestRun = new RunTime();
			fastestShore = -1f;
			fastestTropics = -1f;
			fastestAlpmesa = -1f;
			fastestCaldera = -1f;
			fastestKiln = -1f;
			fastestNadir = -1f;
			fastestBiome4 = -1f;
			averageRun = new RunTime();
			averageShore = -1f;
			averageTropics = -1f;
			averageAlpmesa = -1f;
			averageCaldera = -1f;
			averageKiln = -1f;
			averageNadir = -1f;
			averageBiome4 = -1f;
			totalAttempts = 0;
		}

		public static void GetRunRecords(Func<RunTime, bool> InputCategorizationFunc = null)
		{
			if (SplitsStatsPlugin.Logger != null)
			{
				SplitsStatsPlugin.Logger.LogInfo((object)"Loading run records...");
			}
			ClearInternalSavedRuns();
			int num = 0;
			averageShore = 0f;
			int num2 = 0;
			averageTropics = 0f;
			int num3 = 0;
			averageAlpmesa = 0f;
			int num4 = 0;
			averageCaldera = 0f;
			int num5 = 0;
			averageKiln = 0f;
			int num6 = 0;
			averageNadir = 0f;
			int num7 = 0;
			averageBiome4 = 0f;
			int num8 = 0;
			averageRun.finalTime = 0f;
			totalAttempts = 0;
			foreach (RunTime item in runStorage)
			{
				if (InputCategorizationFunc != null)
				{
					if (!InputCategorizationFunc(item))
					{
						continue;
					}
				}
				else if (CategorizationFunc != null && !CategorizationFunc(item))
				{
					continue;
				}
				if (IsRunActive())
				{
					List<RunTime> list = runStorage;
					if (item == list[list.Count - 1])
					{
						continue;
					}
				}
				totalAttempts++;
				if (item.runFinished && item.finalTime > 0f)
				{
					if (fastestRun.finalTime == -1f || item.finalTime < fastestRun.finalTime)
					{
						fastestRun = new RunTime(item);
					}
					averageRun.finalTime += item.finalTime;
					num++;
				}
				if (item.shoreTime > 0f)
				{
					if (fastestShore == -1f || item.shoreTime < fastestShore)
					{
						fastestShore = item.shoreTime;
					}
					averageShore += item.shoreTime;
					num2++;
				}
				if (item.tropicsTime > 0f)
				{
					if (fastestTropics == -1f || item.tropicsTime < fastestTropics)
					{
						fastestTropics = item.tropicsTime;
					}
					averageTropics += item.tropicsTime;
					num3++;
				}
				if (item.alpmesaTime > 0f)
				{
					if (fastestAlpmesa == -1f || item.alpmesaTime < fastestAlpmesa)
					{
						fastestAlpmesa = item.alpmesaTime;
					}
					averageAlpmesa += item.alpmesaTime;
					num4++;
				}
				if (item.calderaTime > 0f)
				{
					if (fastestCaldera == -1f || item.calderaTime < fastestCaldera)
					{
						fastestCaldera = item.calderaTime;
					}
					averageCaldera += item.calderaTime;
					num5++;
				}
				if (item.kilnTime > 0f)
				{
					if (fastestKiln == -1f || item.kilnTime < fastestKiln)
					{
						fastestKiln = item.kilnTime;
					}
					averageKiln += item.kilnTime;
					num6++;
				}
				if (item.nadirTime > 0f)
				{
					if (fastestNadir == -1f || item.nadirTime < fastestNadir)
					{
						fastestNadir = item.nadirTime;
					}
					averageNadir += item.nadirTime;
					num7++;
				}
				if (item.calderaTime > 0f && item.kilnTime > 0f)
				{
					float num9 = item.calderaTime + item.kilnTime;
					if (fastestBiome4 == -1f || num9 < fastestBiome4)
					{
						fastestBiome4 = num9;
					}
					averageBiome4 += num9;
					num8++;
				}
			}
			if (num2 > 0)
			{
				averageShore /= num2;
			}
			else
			{
				averageShore = -1f;
			}
			if (num3 > 0)
			{
				averageTropics /= num3;
			}
			else
			{
				averageTropics = -1f;
			}
			if (num4 > 0)
			{
				averageAlpmesa /= num4;
			}
			else
			{
				averageAlpmesa = -1f;
			}
			if (num5 > 0)
			{
				averageCaldera /= num5;
			}
			else
			{
				averageCaldera = -1f;
			}
			if (num6 > 0)
			{
				averageKiln /= num6;
			}
			else
			{
				averageKiln = -1f;
			}
			if (num7 > 0)
			{
				averageNadir /= num7;
			}
			else
			{
				averageNadir = -1f;
			}
			if (num8 > 0)
			{
				averageBiome4 /= num8;
			}
			else
			{
				averageBiome4 = -1f;
			}
			if (num > 0)
			{
				averageRun.finalTime /= num;
				averageRun.runFinished = true;
			}
			else
			{
				averageRun.finalTime = -1f;
				averageRun.runFinished = false;
			}
			averageRun.shoreTime = averageShore;
			averageRun.tropicsTime = averageTropics;
			averageRun.alpmesaTime = averageAlpmesa;
			averageRun.calderaTime = averageCaldera;
			averageRun.kilnTime = averageKiln;
			averageRun.nadirTime = averageNadir;
			if (SplitsStatsPlugin.Logger != null)
			{
				SplitsStatsPlugin.Logger.LogInfo((object)$"Loaded times from {totalAttempts} record(s)!");
			}
		}
	}
	public class RunTime
	{
		public string runDate;

		public bool isRealTime;

		public bool runFinished;

		public float finalTime;

		public float shoreTime;

		public float tropicsTime;

		public float alpmesaTime;

		public float calderaTime;

		public float kilnTime;

		public float nadirTime;

		public string gameVersion;

		public string levelName;

		public int ascentDifficulty;

		public int playerCount;

		public bool customRun;

		public uint customRunSettingsHash;

		public bool wasRandomized;

		public int seed;

		public float this[Segment indexSegment]
		{
			get
			{
				//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_0003: Unknown result type (might be due to invalid IL or missing references)
				//IL_0004: 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)
				//IL_0027: Expected I4, but got Unknown
				return (int)indexSegment switch
				{
					0 => shoreTime, 
					1 => tropicsTime, 
					2 => alpmesaTime, 
					3 => calderaTime, 
					4 => kilnTime, 
					6 => nadirTime, 
					_ => throw new IndexOutOfRangeException(), 
				};
			}
			set
			{
				//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_0003: Unknown result type (might be due to invalid IL or missing references)
				//IL_0004: 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)
				//IL_0027: Expected I4, but got Unknown
				switch ((int)indexSegment)
				{
				case 0:
					shoreTime = value;
					break;
				case 1:
					tropicsTime = value;
					break;
				case 2:
					alpmesaTime = value;
					break;
				case 3:
					calderaTime = value;
					break;
				case 4:
					kilnTime = value;
					break;
				case 6:
					nadirTime = value;
					break;
				default:
					throw new IndexOutOfRangeException();
				}
			}
		}

		private static Random HashCodeStartingRandom => new Random(1337);

		public static string GetDateString()
		{
			return DateTime.Now.ToString("g", CultureInfo.CurrentCulture);
		}

		public void UpdateTimeString()
		{
			runDate = GetDateString();
		}

		public RunTime()
		{
			isRealTime = false;
			runFinished = false;
			finalTime = -1f;
			shoreTime = -1f;
			tropicsTime = -1f;
			alpmesaTime = -1f;
			calderaTime = -1f;
			kilnTime = -1f;
			nadirTime = -1f;
			gameVersion = "";
			levelName = "";
			ascentDifficulty = 0;
			playerCount = 0;
			customRun = false;
			customRunSettingsHash = 0u;
			wasRandomized = false;
			seed = 0;
		}

		public RunTime(RunTime original)
		{
			runDate = original.runDate;
			isRealTime = original.isRealTime;
			runFinished = original.runFinished;
			finalTime = original.finalTime;
			shoreTime = original.shoreTime;
			tropicsTime = original.tropicsTime;
			alpmesaTime = original.alpmesaTime;
			calderaTime = original.calderaTime;
			kilnTime = original.kilnTime;
			nadirTime = original.nadirTime;
			gameVersion = original.gameVersion;
			levelName = original.levelName;
			ascentDifficulty = original.ascentDifficulty;
			playerCount = original.playerCount;
			customRun = original.customRun;
			customRunSettingsHash = original.customRunSettingsHash;
			wasRandomized = original.wasRandomized;
			seed = original.seed;
		}

		public override bool Equals(object obj)
		{
			if (obj == null || GetType() != obj.GetType())
			{
				return false;
			}
			RunTime runTime = (RunTime)obj;
			if (runTime.runFinished != runFinished)
			{
				return false;
			}
			if (runTime.finalTime != finalTime)
			{
				return false;
			}
			if (runTime.shoreTime != shoreTime)
			{
				return false;
			}
			if (runTime.tropicsTime != tropicsTime)
			{
				return false;
			}
			if (runTime.alpmesaTime != alpmesaTime)
			{
				return false;
			}
			if (runTime.calderaTime != calderaTime)
			{
				return false;
			}
			if (runTime.kilnTime != kilnTime)
			{
				return false;
			}
			if (runTime.nadirTime != nadirTime)
			{
				return false;
			}
			if (runTime.gameVersion != gameVersion)
			{
				return false;
			}
			if (runTime.levelName != levelName)
			{
				return false;
			}
			if (runTime.ascentDifficulty != ascentDifficulty)
			{
				return false;
			}
			if (runTime.playerCount != playerCount)
			{
				return false;
			}
			if (runTime.isRealTime != isRealTime)
			{
				return false;
			}
			if (runTime.customRun != customRun)
			{
				return false;
			}
			if (runTime.wasRandomized != wasRandomized)
			{
				return false;
			}
			if (runTime.seed != seed)
			{
				return false;
			}
			return true;
		}

		public override int GetHashCode()
		{
			Random hashRandom = HashCodeStartingRandom;
			float num = (runFinished ? (-1234f) : 9876f);
			num *= GetRandomFloat();
			num += finalTime * GetRandomFloat();
			num += shoreTime * GetRandomFloat();
			num += tropicsTime * GetRandomFloat();
			num += alpmesaTime * GetRandomFloat();
			num += calderaTime * GetRandomFloat();
			num += kilnTime * GetRandomFloat();
			num += nadirTime * GetRandomFloat();
			num += (float)gameVersion.GetHashCode() * GetRandomFloat();
			num += (float)levelName.GetHashCode() * GetRandomFloat();
			num += (float)ascentDifficulty * GetRandomFloat();
			num += (float)playerCount * GetRandomFloat();
			num += (isRealTime ? (73806f / MathF.PI) : 1.483f);
			num += (customRun ? 1896.18f : 846.21f);
			num += (float)customRunSettingsHash % 100000f;
			num += (wasRandomized ? (492.6784f * (float)seed) : 38025f);
			byte[] bytes = BitConverter.GetBytes(num);
			return BitConverter.ToInt32(bytes);
			float GetRandomFloat()
			{
				return (float)hashRandom.NextDouble();
			}
		}

		public bool HasTimes()
		{
			if (runFinished && finalTime > 0f)
			{
				return true;
			}
			if (shoreTime > 0f)
			{
				return true;
			}
			if (tropicsTime > 0f)
			{
				return true;
			}
			if (alpmesaTime > 0f)
			{
				return true;
			}
			if (calderaTime > 0f)
			{
				return true;
			}
			if (kilnTime > 0f)
			{
				return true;
			}
			if (nadirTime > 0f)
			{
				return true;
			}
			return false;
		}
	}
	public enum Ascent
	{
		Tenderfoot = -1,
		Default,
		Ascent1,
		Ascent2,
		Ascent3,
		Ascent4,
		Ascent5,
		Ascent6,
		Ascent7,
		Ascent8
	}
	public class SettingsManager
	{
		public static ConfigFile config;

		public static ConfigEntry<bool> isRealTimeConfig;

		public static ConfigEntry<bool> segmentTimersEnabledConfig;

		public static ConfigEntry<bool> sharedBiomeIconsConfig;

		public static ConfigEntry<bool> hiddenSegmentsConfig;

		public static ConfigEntry<bool> timersEnabledConfig;

		public static ConfigEntry<float> uiScaleSizeConfig;

		public static ConfigEntry<bool> showCurrentAttemptNumberConfig;

		public static ConfigEntry<bool> showCurrentHeightConfig;

		public static ConfigEntry<bool> showCurrentRecordConfig;

		public static ConfigEntry<bool> showCurrentSumOfBestConfig;

		public static ConfigEntry<bool> showCurrentSegmentRecordConfig;

		public static ConfigEntry<bool> showCurrentAverageConfig;

		public static ConfigEntry<bool> showCurrentSegmentAverageConfig;

		public static ConfigEntry<bool> showDistanceFromFireConfig;

		public static ConfigEntry<bool> enablePaceConfig;

		public static ConfigEntry<bool> disablePaceCustomRunsConfig;

		public static ConfigEntry<bool> customRunNormalPaceConfig;

		public static ConfigEntry<bool> useAverageRunConfig;

		public static ConfigEntry<bool> showPaceOnStartConfig;

		public static ConfigEntry<float> paceTriggerDistanceConfig;

		public const float MINIMUM_TRIGGER_DISTANCE = 5f;

		public static ConfigEntry<float> paceTimeTriggerConfig;

		public const float MAXIMUM_TRIGGER_TIME = 3600f;

		public static ConfigEntry<bool> showPaceOnEndConfig;

		public static ConfigEntry<bool> showRunPaceConfig;

		public static ConfigEntry<bool> showCurrentCategoryConfig;

		public static ConfigEntry<bool> categorizeByLevelConfig;

		public static ConfigEntry<bool> categorizeByGameVersionConfig;

		public static ConfigEntry<bool> categorizeByPlayerCountConfig;

		public static ConfigEntry<bool> categorizeByAscentConfig;

		public static ConfigEntry<bool> categorizeByTerrainRandomizerConfig;

		public static ConfigEntry<bool> categorizeBySeedConfig;

		public static ConfigEntry<bool> categorizeByCustomRunConfig;

		public static ConfigEntry<int> timerHorizontalOffsetConfig;

		public static ConfigEntry<int> timerVerticalOffsetConfig;

		public static ConfigEntry<int> statsHorizontalOffsetConfig;

		public static ConfigEntry<int> statsVerticalOffsetConfig;

		public static ConfigEntry<bool> statsAutoAdjustConfig;

		public static ConfigEntry<bool> canEditEndScreenTimeConfig;

		public static ConfigEntry<bool> onlyShowFinalRunPaceIfRecordConfig;

		public static ConfigEntry<bool> alwaysShowNadirSegmentConfig;

		public static ConfigEntry<int> precisionInTimerConfig;

		public static ConfigEntry<bool> useInGameTimingConfig;

		public static ConfigEntry<bool> useColorSegmentsConfig;

		public static ConfigEntry<bool> useColorPaceConfig;

		public static ConfigEntry<bool> saveEmptyRunsConfig;

		public static bool isRealTime
		{
			get
			{
				return isRealTimeConfig?.Value ?? false;
			}
			private set
			{
				if (isRealTimeConfig != null)
				{
					isRealTimeConfig.Value = value;
				}
			}
		}

		public static bool segmentTimersEnabled
		{
			get
			{
				return segmentTimersEnabledConfig?.Value ?? true;
			}
			private set
			{
				if (segmentTimersEnabledConfig != null)
				{
					segmentTimersEnabledConfig.Value = value;
				}
			}
		}

		public static bool sharedBiomeIcons
		{
			get
			{
				return sharedBiomeIconsConfig?.Value ?? false;
			}
			private set
			{
				if (sharedBiomeIconsConfig != null)
				{
					sharedBiomeIconsConfig.Value = value;
				}
			}
		}

		public static bool hiddenSegments
		{
			get
			{
				return hiddenSegmentsConfig?.Value ?? false;
			}
			private set
			{
				if (hiddenSegmentsConfig != null)
				{
					hiddenSegmentsConfig.Value = value;
				}
			}
		}

		public static bool timersEnabled
		{
			get
			{
				return timersEnabledConfig?.Value ?? true;
			}
			private set
			{
				if (timersEnabledConfig != null)
				{
					timersEnabledConfig.Value = value;
				}
			}
		}

		public static float uiScaleSize
		{
			get
			{
				return uiScaleSizeConfig?.Value ?? 1f;
			}
			private set
			{
				if (uiScaleSizeConfig != null)
				{
					uiScaleSizeConfig.Value = value;
				}
			}
		}

		public static bool showCurrentAttemptNumber
		{
			get
			{
				return showCurrentAttemptNumberConfig?.Value ?? false;
			}
			private set
			{
				if (showCurrentAttemptNumberConfig != null)
				{
					showCurrentAttemptNumberConfig.Value = value;
				}
			}
		}

		public static bool showCurrentHeight
		{
			get
			{
				return showCurrentHeightConfig?.Value ?? true;
			}
			private set
			{
				if (showCurrentHeightConfig != null)
				{
					showCurrentHeightConfig.Value = value;
				}
			}
		}

		public static bool showCurrentRecord
		{
			get
			{
				return showCurrentRecordConfig?.Value ?? false;
			}
			private set
			{
				if (showCurrentRecordConfig != null)
				{
					showCurrentRecordConfig.Value = value;
				}
			}
		}

		public static bool showCurrentSumOfBest
		{
			get
			{
				return showCurrentSumOfBestConfig?.Value ?? false;
			}
			private set
			{
				if (showCurrentSumOfBestConfig != null)
				{
					showCurrentSumOfBestConfig.Value = value;
				}
			}
		}

		public static bool showCurrentSegmentRecord
		{
			get
			{
				return showCurrentSegmentRecordConfig?.Value ?? false;
			}
			private set
			{
				if (showCurrentSegmentRecordConfig != null)
				{
					showCurrentSegmentRecordConfig.Value = value;
				}
			}
		}

		public static bool showCurrentAverage
		{
			get
			{
				return showCurrentAverageConfig?.Value ?? false;
			}
			private set
			{
				if (showCurrentAverageConfig != null)
				{
					showCurrentAverageConfig.Value = value;
				}
			}
		}

		public static bool showCurrentSegmentAverage
		{
			get
			{
				return showCurrentSegmentAverageConfig?.Value ?? false;
			}
			private set
			{
				if (showCurrentSegmentAverageConfig != null)
				{
					showCurrentSegmentAverageConfig.Value = value;
				}
			}
		}

		public static bool showDistanceFromFire
		{
			get
			{
				return showDistanceFromFireConfig?.Value ?? true;
			}
			private set
			{
				if (showDistanceFromFireConfig != null)
				{
					showDistanceFromFireConfig.Value = value;
				}
			}
		}

		public static bool enablePace
		{
			get
			{
				return enablePaceConfig?.Value ?? true;
			}
			private set
			{
				if (enablePaceConfig != null)
				{
					enablePaceConfig.Value = value;
				}
			}
		}

		public static bool disablePaceCustomRuns
		{
			get
			{
				return disablePaceCustomRunsConfig?.Value ?? true;
			}
			private set
			{
				if (disablePaceCustomRunsConfig != null)
				{
					disablePaceCustomRunsConfig.Value = value;
				}
			}
		}

		public static bool customRunNormalPace
		{
			get
			{
				return customRunNormalPaceConfig?.Value ?? false;
			}
			private set
			{
				if (customRunNormalPaceConfig != null)
				{
					customRunNormalPaceConfig.Value = value;
				}
			}
		}

		public static bool useAverageRun
		{
			get
			{
				return useAverageRunConfig?.Value ?? false;
			}
			private set
			{
				if (useAverageRunConfig != null)
				{
					useAverageRunConfig.Value = value;
				}
			}
		}

		public static bool showPaceOnStart
		{
			get
			{
				return showPaceOnStartConfig?.Value ?? false;
			}
			private set
			{
				if (showPaceOnStartConfig != null)
				{
					showPaceOnStartConfig.Value = value;
				}
			}
		}

		public static float paceTriggerDistance
		{
			get
			{
				return paceTriggerDistanceConfig?.Value ?? 170f;
			}
			private set
			{
				if (paceTriggerDistanceConfig != null)
				{
					paceTriggerDistanceConfig.Value = value;
				}
			}
		}

		public static bool showPaceNearGoals => paceTriggerDistance > 5f;

		public static float paceTimeTrigger
		{
			get
			{
				return paceTimeTriggerConfig?.Value ?? (-60f);
			}
			private set
			{
				if (paceTimeTriggerConfig != null)
				{
					paceTimeTriggerConfig.Value = value;
				}
			}
		}

		public static bool showPaceOnTimeTrigger => paceTimeTrigger < 3600f;

		public static bool showPaceOnEnd
		{
			get
			{
				return showPaceOnEndConfig?.Value ?? true;
			}
			private set
			{
				if (showPaceOnEndConfig != null)
				{
					showPaceOnEndConfig.Value = value;
				}
			}
		}

		public static bool showRunPace
		{
			get
			{
				return showRunPaceConfig?.Value ?? false;
			}
			private set
			{
				if (showRunPaceConfig != null)
				{
					showRunPaceConfig.Value = value;
				}
			}
		}

		public static bool paceTextEnabled => enablePace && (!RunSettings.IsCustomRun || !disablePaceCustomRuns) && (showRunPace || showPaceOnEnd || showPaceOnTimeTrigger || showPaceNearGoals || showPaceOnStart);

		public static bool showCurrentCategory
		{
			get
			{
				return showCurrentCategoryConfig?.Value ?? false;
			}
			private set
			{
				if (showCurrentCategoryConfig != null)
				{
					showCurrentCategoryConfig.Value = value;
				}
			}
		}

		public static bool categorizeByLevel
		{
			get
			{
				return categorizeByLevelConfig?.Value ?? false;
			}
			private set
			{
				if (categorizeByLevelConfig != null)
				{
					categorizeByLevelConfig.Value = value;
				}
			}
		}

		public static bool categorizeByGameVersion
		{
			get
			{
				return categorizeByGameVersionConfig?.Value ?? false;
			}
			private set
			{
				if (categorizeByGameVersionConfig != null)
				{
					categorizeByGameVersionConfig.Value = value;
				}
			}
		}

		public static bool categorizeByPlayerCount
		{
			get
			{
				return categorizeByPlayerCountConfig?.Value ?? true;
			}
			private set
			{
				if (categorizeByPlayerCountConfig != null)
				{
					categorizeByPlayerCountConfig.Value = value;
				}
			}
		}

		public static bool categorizeByAscent
		{
			get
			{
				return categorizeByAscentConfig?.Value ?? true;
			}
			private set
			{
				if (categorizeByAscentConfig != null)
				{
					categorizeByAscentConfig.Value = value;
				}
			}
		}

		public static bool categorizeByTerrainRandomizer
		{
			get
			{
				return categorizeByTerrainRandomizerConfig?.Value ?? true;
			}
			private set
			{
				if (categorizeByTerrainRandomizerConfig != null)
				{
					categorizeByTerrainRandomizerConfig.Value = value;
				}
			}
		}

		public static bool categorizeBySeed
		{
			get
			{
				return categorizeBySeedConfig?.Value ?? false;
			}
			private set
			{
				if (categorizeBySeedConfig != null)
				{
					categorizeBySeedConfig.Value = value;
				}
			}
		}

		public static bool categorizeByCustomRun
		{
			get
			{
				return categorizeByCustomRunConfig?.Value ?? true;
			}
			private set
			{
				if (categorizeByCustomRunConfig != null)
				{
					categorizeByCustomRunConfig.Value = value;
				}
			}
		}

		public static bool isCategorized => categorizeByLevel || categorizeByGameVersion || categorizeByAscent || categorizeByPlayerCount || categorizeByTerrainRandomizer || categorizeBySeed || categorizeByCustomRun;

		public static bool hasVisibleCategoryLabel => Ascents.currentAscent != 0 || (showCurrentCategory && (categorizeByPlayerCount || categorizeByLevel || categorizeByCustomRun || (categorizeByTerrainRandomizer && RunSaveManager.currentRun.wasRandomized)));

		public static int timerHorizontalOffset
		{
			get
			{
				return timerHorizontalOffsetConfig?.Value ?? 0;
			}
			private set
			{
				if (timerHorizontalOffsetConfig != null)
				{
					timerHorizontalOffsetConfig.Value = value;
				}
			}
		}

		public static int timerVerticalOffset
		{
			get
			{
				return timerVerticalOffsetConfig?.Value ?? 0;
			}
			private set
			{
				if (timerVerticalOffsetConfig != null)
				{
					timerVerticalOffsetConfig.Value = value;
				}
			}
		}

		public static Vector2 timerVectorOffset => new Vector2((float)timerHorizontalOffset, (float)timerVerticalOffset);

		public static int statsHorizontalOffset
		{
			get
			{
				return statsHorizontalOffsetConfig?.Value ?? 0;
			}
			private set
			{
				if (statsHorizontalOffsetConfig != null)
				{
					statsHorizontalOffsetConfig.Value = value;
				}
			}
		}

		public static int statsVerticalOffset
		{
			get
			{
				return statsVerticalOffsetConfig?.Value ?? 0;
			}
			private set
			{
				if (statsVerticalOffsetConfig != null)
				{
					statsVerticalOffsetConfig.Value = value;
				}
			}
		}

		public static Vector2 statsVectorOffset => new Vector2((float)statsHorizontalOffset, (float)statsVerticalOffset);

		public static bool statsAutoAdjust
		{
			get
			{
				return statsAutoAdjustConfig?.Value ?? true;
			}
			private set
			{
				if (statsAutoAdjustConfig != null)
				{
					statsAutoAdjustConfig.Value = value;
				}
			}
		}

		public static bool canEditEndScreenTime
		{
			get
			{
				return canEditEndScreenTimeConfig?.Value ?? true;
			}
			private set
			{
				if (canEditEndScreenTimeConfig != null)
				{
					canEditEndScreenTimeConfig.Value = value;
				}
			}
		}

		public static bool onlyShowFinalRunPaceIfRecord
		{
			get
			{
				return onlyShowFinalRunPaceIfRecordConfig?.Value ?? false;
			}
			private set
			{
				if (onlyShowFinalRunPaceIfRecordConfig != null)
				{
					onlyShowFinalRunPaceIfRecordConfig.Value = value;
				}
			}
		}

		public static bool alwaysShowNadirSegment
		{
			get
			{
				return alwaysShowNadirSegmentConfig?.Value ?? false;
			}
			private set
			{
				if (alwaysShowNadirSegmentConfig != null)
				{
					alwaysShowNadirSegmentConfig.Value = value;
				}
			}
		}

		public static int precisionInTimer
		{
			get
			{
				return precisionInTimerConfig?.Value ?? 1;
			}
			private set
			{
				if (precisionInTimerConfig != null)
				{
					precisionInTimerConfig.Value = value;
				}
			}
		}

		public static bool useInGameTiming
		{
			get
			{
				return useInGameTimingConfig?.Value ?? false;
			}
			private set
			{
				if (useInGameTimingConfig != null)
				{
					useInGameTimingConfig.Value = value;
				}
			}
		}

		public static bool useColorSegments
		{
			get
			{
				return useColorSegmentsConfig?.Value ?? true;
			}
			private set
			{
				if (useColorSegmentsConfig != null)
				{
					useColorSegmentsConfig.Value = value;
				}
			}
		}

		public static bool useColorPace
		{
			get
			{
				return useColorPaceConfig?.Value ?? true;
			}
			private set
			{
				if (useColorPaceConfig != null)
				{
					useColorPaceConfig.Value = value;
				}
			}
		}

		public static bool saveEmptyRuns
		{
			get
			{
				return saveEmptyRunsConfig?.Value ?? true;
			}
			private set
			{
				if (saveEmptyRunsConfig != null)
				{
					saveEmptyRunsConfig.Value = value;
				}
			}
		}

		public static void InitSettingsManager(ConfigFile inputConfig)
		{
			config = inputConfig;
			if (SplitsStatsPlugin.Logger != null)
			{
				SplitsStatsPlugin.Logger.LogInfo((object)"Initialized Settings Manager!");
			}
		}

		public static void LoadConfigBindings()
		{
			if (config != null)
			{
				timersEnabledConfig = config.Bind<bool>("1. General", "Enable Timer", timersEnabled, "Show the main speedrunning timer.");
				segmentTimersEnabledConfig = config.Bind<bool>("1. General", "Show Segment Timers", segmentTimersEnabled, "Show the times for individual biome segments.");
				sharedBiomeIconsConfig = config.Bind<bool>("1. General", "Use Shared Biome Icons", sharedBiomeIcons, "Segment timers' icons initially use shared icons that don't reveal the run's selected biome until they're reached. Set to false to always display the run's biomes at the start of each run.");
				hiddenSegmentsConfig = config.Bind<bool>("1. General", "Hidden Segments", hiddenSegments, "If true, segment timers are hidden from displaying until their corresponding timer begins as the run progresses.");
				isRealTimeConfig = config.Bind<bool>("1. General", "Use Real Time", isRealTime, "Use real system time instead of in-game time. Doing so will allow the timer to keep running if the game is paused when playing solo.");
				uiScaleSizeConfig = config.Bind<float>("1. General", "UI Scale Multiplier", uiScaleSize, "Scale the size of the mod's UI. Default is 1.0 (100% the original size)");
				showCurrentAttemptNumberConfig = config.Bind<bool>("1. General", "Show Current Attempt Number", showCurrentAttemptNumber, "Show the player's current run attempt number. This number is based on the number of saved runs that fit the categorization settings.");
				showCurrentRecordConfig = config.Bind<bool>("1. General", "Show Record Time", showCurrentRecord, "Show the player's current record time based on the categorization settings.");
				showCurrentSumOfBestConfig = config.Bind<bool>("1. General", "Show Sum of Best Time", showCurrentSumOfBest, "Show the player's current sum of best time based on the categorization settings.");
				showCurrentSegmentRecordConfig = config.Bind<bool>("1. General", "Show Segment Record Time", showCurrentSegmentRecord, "Show the player's current segment record time based on the categorization settings.");
				showCurrentSegmentAverageConfig = config.Bind<bool>("1. General", "Show Average Time", showCurrentSegmentAverage, "Show the player's current average time based on the categorization settings.");
				showCurrentAverageConfig = config.Bind<bool>("1. General", "Show Segment Average Time", showCurrentAverage, "Show the player's current segment average time based on the categorization settings.");
				showCurrentHeightConfig = config.Bind<bool>("1. General", "Show Current Height", showCurrentHeight, "Show the player's current height/altitude.");
				showDistanceFromFireConfig = config.Bind<bool>("1. General", "Show Distance From Campfire", showDistanceFromFire, "Show the player's current distance from the next campfire or the Peak if in The Kiln.");
				enablePaceConfig = config.Bind<bool>("2. Run Pace/Intervals", "Enable Pace/Intervals", enablePace, "Display how far ahead or behind you are from your best record next to each timer. The runs used for pacing are based on the categorization settings.");
				disablePaceCustomRunsConfig = config.Bind<bool>("2. Run Pace/Intervals", "Disable Pace/Intervals for Custom Runs", disablePaceCustomRuns, "Set to true to hide the pace/interval during custom runs and miniruns.");
				customRunNormalPaceConfig = config.Bind<bool>("2. Run Pace/Intervals", "Custom Run Paces Use Normal Run Times", customRunNormalPace, "Set to true to have pace/interval timers during custom runs display times earned from normal runs.");
				useAverageRunConfig = config.Bind<bool>("2. Run Pace/Intervals", "Display Average Pace", useAverageRun, "Set to true to display your average times instead of the record time. Gold splits now display personal bests.");
				showPaceOnStartConfig = config.Bind<bool>("2. Run Pace/Intervals", "Show On Timer/Segment Start", showPaceOnStart, "Show the current run pace/interval as soon as the timer starts.");
				showPaceOnEndConfig = config.Bind<bool>("2. Run Pace/Intervals", "Show On Segment Ends", showPaceOnEnd, "Show the pace/intervals when each segment time is ended.");
				paceTriggerDistanceConfig = config.Bind<float>("2. Run Pace/Intervals", "Show When Near End", paceTriggerDistance, "Trigger distance for when the player nears the next campfire/key point. The full run pace/interval displays when reaching the Peak. Set to less than 5.0 to disable.");
				paceTimeTriggerConfig = config.Bind<float>("2. Run Pace/Intervals", "Show At Specific Time", paceTimeTrigger, "Show the pace/interval when it reaches the specified time (in seconds). For example, set this to -60.0 if you'd like the pace timer to display when the current segment's pace reaches -1:00.0 from personal best. The full run pace/interval displays when reaching the Peak. Set to more than 3600.0 (one hour) to disable.");
				showRunPaceConfig = config.Bind<bool>("2. Run Pace/Intervals", "Always Show Run Pace/Interval", showRunPace, "Always show the pace of the entire run.");
				showCurrentCategoryConfig = config.Bind<bool>("3. Categorizing", "Show Current Category", showCurrentCategory, "Edit the ascent text to also display the current category based on categorization settings.");
				categorizeByLevelConfig = config.Bind<bool>("3. Categorizing", "By Daily Mountain"