Decompiled source of ClimbInfoTracker v0.5.1

plugins/com.github.LengSword.ClimbInfoTracker.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ClimbInfoTracker.Compatibility;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using PLL.Library;
using Peak;
using Peak.Network;
using Photon.Pun;
using Photon.Realtime;
using Portningsbolaget.Platforms;
using Steamworks;
using TMPro;
using TerrainRandomiser;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core;
using Zorro.Core.Editor;
using Zorro.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.LengSword.ClimbInfoTracker")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.1.0")]
[assembly: AssemblyInformationalVersion("0.5.1+26cc5347d83bd0303e058b6a80e4aac3ec44449e")]
[assembly: AssemblyProduct("com.github.LengSword.ClimbInfoTracker")]
[assembly: AssemblyTitle("ClimbInfoTracker")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://codeberg.org/yls-peak-mods/ClimbInfoTracker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.5.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[CompilerGenerated]
internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
	private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T>
	{
		object IEnumerator.Current => _item;

		T IEnumerator<T>.Current => _item;

		public Enumerator(T item)
		{
			_item = item;
		}

		bool IEnumerator.MoveNext()
		{
			if (!_moveNextCalled)
			{
				return _moveNextCalled = true;
			}
			return false;
		}

		void IEnumerator.Reset()
		{
			_moveNextCalled = false;
		}

		void IDisposable.Dispose()
		{
		}
	}

	int ICollection.Count => 1;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object IList.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int IReadOnlyCollection<T>.Count => 1;

	T IReadOnlyList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
	}

	int ICollection<T>.Count => 1;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlySingleElementList(T item)
	{
		_item = item;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection.CopyTo(Array array, int index)
	{
		array.SetValue(_item, index);
	}

	int IList.Add(object value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object value)
	{
		return EqualityComparer<T>.Default.Equals(_item, (T)value);
	}

	int IList.IndexOf(object value)
	{
		if (!EqualityComparer<T>.Default.Equals(_item, (T)value))
		{
			return -1;
		}
		return 0;
	}

	void IList.Insert(int index, object value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return EqualityComparer<T>.Default.Equals(_item, item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		array[arrayIndex] = _item;
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		if (!EqualityComparer<T>.Default.Equals(_item, item))
		{
			return -1;
		}
		return 0;
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace ClimbInfoTracker
{
	internal static class ClimbOutcome
	{
		internal const string InProgress = "InProgress";

		internal const string Summited = "Summited";

		internal const string Failed = "Failed";

		internal const string Abandoned = "Abandoned";

		internal static bool IsCompleted(string outcome)
		{
			switch (outcome)
			{
			case "Summited":
			case "Failed":
			case "Abandoned":
				return true;
			default:
				return false;
			}
		}
	}
	internal static class ClimbNetworkMode
	{
		internal const string Offline = "Offline";

		internal const string Multiplayer = "Multiplayer";
	}
	internal enum RunIdConfirmationResult
	{
		NoChange,
		Confirmed,
		Resumed,
		Conflict
	}
	[DataContract]
	internal sealed class ClimbRecord
	{
		[DataMember(Order = 1)]
		public string RunId { get; set; } = "";

		[DataMember(Order = 2)]
		public string StartedAtUtc { get; set; } = "";

		[DataMember(Order = 3)]
		public string EndedAtUtc { get; set; } = "";

		[DataMember(Order = 4)]
		public string Outcome { get; set; } = "InProgress";

		[DataMember(Order = 5)]
		public float DurationSeconds { get; set; }

		[DataMember(Order = 6)]
		public float CurrentHeightMeters { get; set; }

		[DataMember(Order = 7)]
		public int Ascent { get; set; }

		[DataMember(Order = 8)]
		public int PlayerCount { get; set; } = 1;

		[DataMember(Order = 9)]
		public bool IsCustomRun { get; set; }

		[DataMember(Order = 10)]
		public bool IsMiniRun { get; set; }

		[DataMember(Order = 11)]
		public string Level { get; set; } = "";

		[DataMember(Order = 12)]
		public string Biome { get; set; } = "";

		[DataMember(Order = 13)]
		public bool TerrainRandomiserEnabled { get; set; }

		[DataMember(Order = 14)]
		public int TerrainRandomiserSeed { get; set; } = -1;

		[DataMember(Order = 15)]
		public string TerrainRandomiserMapSettingsBrotliBase64 { get; set; } = "";

		[DataMember(Order = 16)]
		public string NetworkMode { get; set; } = "";

		[DataMember(Order = 17)]
		public string PhotonRoomName { get; set; } = "";

		[DataMember(Order = 18)]
		public List<MapBiomeInfo> MapBiomes { get; set; } = new List<MapBiomeInfo>();

		[DataMember(Order = 19, EmitDefaultValue = false)]
		public int? PLLMapSeed { get; set; }

		[DataMember(Order = 20)]
		public List<int> MapSegmentBiomeIndices { get; set; } = new List<int>();

		[DataMember(Order = 21)]
		public List<ClimbPlayerInfo> OtherPlayers { get; set; } = new List<ClimbPlayerInfo>();

		[DataMember(Order = 22)]
		public bool RunIdConfirmed { get; set; }

		[DataMember(Order = 23)]
		public bool TrueFinalAscentEnabled { get; set; }

		[DataMember(Order = 24, EmitDefaultValue = false)]
		public int? TFAMapSeed { get; set; }

		[DataMember(Order = 25)]
		public bool TFAApocalypseEnabled { get; set; }

		[DataMember(Order = 26, EmitDefaultValue = false)]
		public string TfaCurrentBiomeId { get; set; } = "";

		[DataMember(Order = 27, EmitDefaultValue = false)]
		public List<ClimbSegmentTiming>? SegmentTimings { get; set; }

		[DataMember(Order = 28, EmitDefaultValue = false)]
		public string SegmentTimingMapKey { get; set; } = "";
	}
	[DataContract]
	internal sealed class ClimbPlayerInfo
	{
		[DataMember(Order = 1)]
		public string Platform { get; set; } = "";

		[DataMember(Order = 2)]
		public string PlatformUserId { get; set; } = "";

		[DataMember(Order = 3)]
		public string DisplayName { get; set; } = "";
	}
	[DataContract]
	internal enum TfaBiomeScaleAxis
	{
		[EnumMember]
		Height,
		[EnumMember]
		Length
	}
	[DataContract]
	internal sealed class MapBiomeInfo
	{
		[DataMember(Order = 1)]
		public BiomeType BiomeType { get; set; }

		[DataMember(Order = 2)]
		public string Variant { get; set; } = "";

		[DataMember(Order = 3)]
		public bool? OpenTomb { get; set; }

		[DataMember(Order = 4, EmitDefaultValue = false)]
		public string TitleKey { get; set; } = "";

		[DataMember(Order = 5, EmitDefaultValue = false)]
		public int? TfaSegmentIndex { get; set; }

		[DataMember(Order = 6, EmitDefaultValue = false)]
		public int? TfaChainIndex { get; set; }

		[DataMember(Order = 7, EmitDefaultValue = false)]
		public string TfaBiomeId { get; set; } = "";

		[DataMember(Order = 8, EmitDefaultValue = false)]
		public Dictionary<string, string> TfaBiomeNames { get; set; } = new Dictionary<string, string>();

		[DataMember(Order = 9, EmitDefaultValue = false)]
		public bool IsRouteTerminal { get; set; }

		[DataMember(Order = 10, EmitDefaultValue = false)]
		public int? TfaScalePercent { get; set; }

		[DataMember(Order = 11, EmitDefaultValue = false)]
		public TfaBiomeScaleAxis? TfaScaleAxis { get; set; }
	}
	[DataContract]
	internal sealed class ClimbHistoryData
	{
		[DataMember(Order = 1)]
		public int SchemaVersion { get; set; } = 16;

		[DataMember(Order = 2)]
		public List<ClimbRecord> Records { get; set; } = new List<ClimbRecord>();

		[DataMember(Order = 3, EmitDefaultValue = false)]
		public ClimbRecord? ActiveRecord { get; set; }
	}
	internal sealed class ClimbHistory
	{
		private const int CurrentSchemaVersion = 16;

		private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings
		{
			ConstructorHandling = (ConstructorHandling)1,
			DateParseHandling = (DateParseHandling)0,
			Converters = { (JsonConverter)new StringEnumConverter() }
		};

		private readonly ClimbHistoryStorage _storage;

		private ClimbHistoryData _data;

		internal ClimbRecord? ActiveRecord => _data.ActiveRecord;

		internal ClimbHistory()
		{
			string path = Path.Combine(Application.persistentDataPath, "ClimbInfoTracker", "ClimbInfoTracker.json");
			_storage = new ClimbHistoryStorage(path, Deserialize);
			_data = _storage.Load();
		}

		internal IReadOnlyList<ClimbRecord> GetRecords()
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord == null)
			{
				return _data.Records.ToArray();
			}
			List<ClimbRecord> records = _data.Records;
			List<ClimbRecord> list = new List<ClimbRecord>(1 + records.Count);
			list.AddRange(records);
			list.Add(activeRecord);
			return list;
		}

		internal void Begin(ClimbRecord record)
		{
			if (_data.ActiveRecord != null)
			{
				if (_data.ActiveRecord.RunId == record.RunId)
				{
					return;
				}
				FinalizeActive("Abandoned", _data.ActiveRecord.DurationSeconds);
			}
			NormalizeRecord(record);
			_data.ActiveRecord = record;
			Save(flushToDisk: true);
		}

		internal bool TryResumeMultiplayerRun(ClimbRecord currentRecord, float? elapsedSeconds)
		{
			if (currentRecord.NetworkMode != "Multiplayer" || string.IsNullOrWhiteSpace(currentRecord.PhotonRoomName) || !currentRecord.RunIdConfirmed)
			{
				return false;
			}
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord != null && IsRunResumeCandidate(activeRecord, currentRecord.PhotonRoomName, currentRecord.RunId))
			{
				RefreshResumedRecord(activeRecord, currentRecord, elapsedSeconds);
				Save(flushToDisk: true);
				return true;
			}
			for (int num = _data.Records.Count - 1; num >= 0; num--)
			{
				ClimbRecord climbRecord = _data.Records[num];
				if (IsRunResumeCandidate(climbRecord, currentRecord.PhotonRoomName, currentRecord.RunId))
				{
					if (_data.ActiveRecord != null)
					{
						FinalizeActive("Abandoned", _data.ActiveRecord.DurationSeconds);
					}
					_data.Records.Remove(climbRecord);
					RefreshResumedRecord(climbRecord, currentRecord, elapsedSeconds);
					_data.ActiveRecord = climbRecord;
					Save(flushToDisk: true);
					return true;
				}
			}
			return false;
		}

		internal void Snapshot(float durationSeconds, float currentHeightMeters, string biome, int playerCount, string networkMode, string photonRoomName, string? tfaCurrentBiomeId = null)
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord != null)
			{
				activeRecord.DurationSeconds = durationSeconds;
				activeRecord.CurrentHeightMeters = Math.Max(activeRecord.CurrentHeightMeters, currentHeightMeters);
				UpdateBiome(activeRecord, biome, tfaCurrentBiomeId);
				activeRecord.PlayerCount = Math.Max(activeRecord.PlayerCount, Math.Max(1, playerCount));
				UpdateNetworkState(activeRecord, networkMode, photonRoomName);
				Save();
			}
		}

		internal void ObservePlayers(IReadOnlyList<ClimbPlayerInfo> players, int playerCount)
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord != null)
			{
				bool flag = false;
				int num = Math.Max(activeRecord.PlayerCount, Math.Max(1, playerCount));
				if (num != activeRecord.PlayerCount)
				{
					activeRecord.PlayerCount = num;
					flag = true;
				}
				ClimbRecord climbRecord = activeRecord;
				if (climbRecord.OtherPlayers == null)
				{
					List<ClimbPlayerInfo> list = (climbRecord.OtherPlayers = new List<ClimbPlayerInfo>());
				}
				if (flag | MergePlayers(activeRecord.OtherPlayers, players))
				{
					Save();
				}
			}
		}

		internal void EnsureActiveMapBiomeCapture(MapBiomeCapture capture)
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord != null && capture.MapBiomes.Count != 0)
			{
				bool flag = false;
				if (activeRecord.MapBiomes == null || activeRecord.MapBiomes.Count == 0)
				{
					activeRecord.MapBiomes = CopyMapBiomes(capture.MapBiomes);
					flag = true;
				}
				if ((activeRecord.MapSegmentBiomeIndices == null || activeRecord.MapSegmentBiomeIndices.Count == 0) && SameTfaRoute(activeRecord.MapBiomes, capture.MapBiomes))
				{
					activeRecord.MapSegmentBiomeIndices = CopyMapSegmentBiomeIndices(capture.SegmentBiomeIndices);
					flag = true;
				}
				if (flag)
				{
					Save();
				}
			}
		}

		internal bool UpdateActiveMapBiomeDetails(int index, MapBiomeInfo details)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord == null || activeRecord.MapBiomes == null || index < 0 || index >= activeRecord.MapBiomes.Count)
			{
				return false;
			}
			MapBiomeInfo mapBiomeInfo = activeRecord.MapBiomes[index];
			if (mapBiomeInfo.BiomeType != details.BiomeType)
			{
				return false;
			}
			bool flag = false;
			if (!string.IsNullOrWhiteSpace(details.Variant) && !string.Equals(mapBiomeInfo.Variant, details.Variant, StringComparison.Ordinal))
			{
				mapBiomeInfo.Variant = details.Variant;
				flag = true;
			}
			if (details.OpenTomb.HasValue && mapBiomeInfo.OpenTomb != details.OpenTomb)
			{
				mapBiomeInfo.OpenTomb = details.OpenTomb;
				flag = true;
			}
			if (flag)
			{
				Save();
			}
			return true;
		}

		internal void UpdateActiveTerrainRandomiser(bool enabled, int seed, string mapSettingsBrotliBase64)
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord != null)
			{
				activeRecord.TerrainRandomiserEnabled = enabled;
				activeRecord.TerrainRandomiserSeed = (enabled ? seed : (-1));
				activeRecord.TerrainRandomiserMapSettingsBrotliBase64 = (enabled ? mapSettingsBrotliBase64 : "");
				Save();
			}
		}

		internal void EnsureActivePLLMapSeed(int seed)
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord != null && !activeRecord.PLLMapSeed.HasValue)
			{
				activeRecord.PLLMapSeed = seed;
				Save();
			}
		}

		internal void EnsureActiveTfaApocalypseEnabled()
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord != null && !activeRecord.TFAApocalypseEnabled)
			{
				activeRecord.TFAApocalypseEnabled = true;
				Save();
			}
		}

		internal void SetActiveTfaEnabled(bool enabled)
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord != null && activeRecord.TrueFinalAscentEnabled != enabled)
			{
				activeRecord.TrueFinalAscentEnabled = enabled;
				if (enabled)
				{
					activeRecord.PLLMapSeed = null;
					activeRecord.TerrainRandomiserEnabled = false;
					activeRecord.TerrainRandomiserSeed = -1;
					activeRecord.TerrainRandomiserMapSettingsBrotliBase64 = "";
				}
				Save();
			}
		}

		internal void UpdateActiveTfaRoute(int seed, IReadOnlyList<MapBiomeInfo> route)
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord == null || route.Count == 0)
			{
				return;
			}
			List<MapBiomeInfo> list = CopyMapBiomes(route);
			bool flag = activeRecord.TrueFinalAscentEnabled && activeRecord.TFAMapSeed == seed && SameTfaRoute(activeRecord.MapBiomes, list);
			if (!flag)
			{
				List<ClimbSegmentTiming>? segmentTimings = activeRecord.SegmentTimings;
				if (segmentTimings != null && segmentTimings.Count > 0)
				{
					activeRecord.SegmentTimings = new List<ClimbSegmentTiming>();
				}
			}
			if (flag)
			{
				PreserveTfaTerminalEntries(activeRecord.MapBiomes, list);
				bool flag2 = false;
				for (int i = 0; i < Math.Min(activeRecord.MapBiomes.Count, list.Count); i++)
				{
					list[i].Variant = activeRecord.MapBiomes[i].Variant;
					list[i].OpenTomb = activeRecord.MapBiomes[i].OpenTomb;
					MergeTfaBiomeNames(activeRecord.MapBiomes[i], list[i]);
					PreserveTfaScale(activeRecord.MapBiomes[i], list[i]);
					flag2 |= !SameTfaBiomeNames(activeRecord.MapBiomes[i], list[i]);
				}
				if (!flag2 && SameMapBiomeRoute(activeRecord.MapBiomes, list))
				{
					return;
				}
			}
			activeRecord.TrueFinalAscentEnabled = true;
			activeRecord.TFAMapSeed = seed;
			activeRecord.MapBiomes = list;
			activeRecord.MapSegmentBiomeIndices.Clear();
			activeRecord.PLLMapSeed = null;
			activeRecord.TerrainRandomiserEnabled = false;
			activeRecord.TerrainRandomiserSeed = -1;
			activeRecord.TerrainRandomiserMapSettingsBrotliBase64 = "";
			Save();
		}

		internal void SaveSegmentTimings()
		{
			Save(flushToDisk: true);
		}

		internal void EnsureRouteTerminal(BiomeType biomeType)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Invalid comparison between Unknown and I4
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Invalid comparison between Unknown and I4
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord == null || activeRecord.MapBiomes.Exists((MapBiomeInfo biome) => biome.IsRouteTerminal && biome.BiomeType == biomeType))
			{
				return;
			}
			MapBiomeInfo item = new MapBiomeInfo
			{
				BiomeType = biomeType,
				TitleKey = (((int)biomeType == 5) ? "PEAK" : "AREA_VOID"),
				IsRouteTerminal = true
			};
			int num = activeRecord.MapBiomes.FindIndex((MapBiomeInfo biome) => biome.IsRouteTerminal && (int)biome.BiomeType == 17);
			if ((int)biomeType == 5 && num >= 0)
			{
				activeRecord.MapBiomes.Insert(num, item);
				for (int num2 = 0; num2 < activeRecord.MapSegmentBiomeIndices.Count; num2++)
				{
					if (activeRecord.MapSegmentBiomeIndices[num2] >= num)
					{
						activeRecord.MapSegmentBiomeIndices[num2]++;
					}
				}
			}
			else
			{
				activeRecord.MapBiomes.Add(item);
			}
		}

		internal RunIdConfirmationResult ConfirmActiveRunId(string runId, float? elapsedSeconds)
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord == null || string.IsNullOrWhiteSpace(runId))
			{
				return RunIdConfirmationResult.NoChange;
			}
			if (activeRecord.RunIdConfirmed)
			{
				if (!string.Equals(activeRecord.RunId, runId, StringComparison.OrdinalIgnoreCase))
				{
					return RunIdConfirmationResult.Conflict;
				}
				return RunIdConfirmationResult.NoChange;
			}
			if (string.Equals(activeRecord.RunId, runId, StringComparison.OrdinalIgnoreCase))
			{
				activeRecord.RunIdConfirmed = true;
				Save(flushToDisk: true);
				return RunIdConfirmationResult.Confirmed;
			}
			if (activeRecord.NetworkMode == "Multiplayer" && !string.IsNullOrWhiteSpace(activeRecord.PhotonRoomName))
			{
				for (int num = _data.Records.Count - 1; num >= 0; num--)
				{
					ClimbRecord climbRecord = _data.Records[num];
					if (IsRunResumeCandidate(climbRecord, activeRecord.PhotonRoomName, runId))
					{
						activeRecord.RunId = runId;
						activeRecord.RunIdConfirmed = true;
						_data.Records.RemoveAt(num);
						RefreshResumedRecord(climbRecord, activeRecord, elapsedSeconds);
						_data.ActiveRecord = climbRecord;
						Save(flushToDisk: true);
						return RunIdConfirmationResult.Resumed;
					}
				}
			}
			activeRecord.RunId = runId;
			activeRecord.RunIdConfirmed = true;
			Save(flushToDisk: true);
			return RunIdConfirmationResult.Confirmed;
		}

		internal bool DeleteRecord(string runId)
		{
			if (string.IsNullOrWhiteSpace(runId))
			{
				return false;
			}
			bool flag = _data.Records.RemoveAll((ClimbRecord record) => record.RunId == runId) > 0;
			if (_data.ActiveRecord?.RunId == runId)
			{
				_data.ActiveRecord = null;
				flag = true;
			}
			if (flag)
			{
				Save(flushToDisk: true);
			}
			return flag;
		}

		internal bool TryDeleteRecords(IReadOnlyCollection<string> runIds, out int deletedCount)
		{
			//IL_00b1: Expected O, but got Unknown
			deletedCount = 0;
			HashSet<string> candidates = new HashSet<string>(runIds, StringComparer.OrdinalIgnoreCase);
			List<ClimbRecord> list = _data.Records.FindAll((ClimbRecord record) => !candidates.Contains(record.RunId) || !ClimbOutcome.IsCompleted(record.Outcome) || string.Equals(record.RunId, _data.ActiveRecord?.RunId, StringComparison.OrdinalIgnoreCase));
			int num = _data.Records.Count - list.Count;
			if (num == 0)
			{
				return true;
			}
			ClimbHistoryData climbHistoryData = new ClimbHistoryData
			{
				SchemaVersion = _data.SchemaVersion,
				Records = list,
				ActiveRecord = _data.ActiveRecord
			};
			try
			{
				string json = JsonConvert.SerializeObject((object)climbHistoryData, (Formatting)0, JsonSettings);
				if (!_storage.Save(json, flushToDisk: true))
				{
					return false;
				}
			}
			catch (JsonException ex)
			{
				JsonException arg = ex;
				Plugin.Logger.LogError((object)$"Failed to serialize climb history: {arg}");
				return false;
			}
			_data.Records = list;
			deletedCount = num;
			return true;
		}

		internal void Complete(string outcome, float durationSeconds, float currentHeightMeters, string biome, int playerCount, string networkMode, string photonRoomName, string? tfaCurrentBiomeId = null)
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord != null)
			{
				activeRecord.CurrentHeightMeters = Math.Max(activeRecord.CurrentHeightMeters, currentHeightMeters);
				UpdateBiome(activeRecord, biome, tfaCurrentBiomeId);
				activeRecord.PlayerCount = Math.Max(activeRecord.PlayerCount, Math.Max(1, playerCount));
				UpdateNetworkState(activeRecord, networkMode, photonRoomName);
				FinalizeActive(outcome, durationSeconds);
			}
		}

		internal void CorrectCompletedRunTime(ClimbRecord record, string runId, float time, ClimbTimingStop stop)
		{
			if (_data.Records.Contains(record) && !(record.RunId != runId) && ClimbOutcome.IsCompleted(record.Outcome))
			{
				record.DurationSeconds = time;
				stop.Correct(record, time);
				Save(flushToDisk: true);
			}
		}

		private static void UpdateBiome(ClimbRecord record, string biome, string? tfaCurrentBiomeId)
		{
			if (!string.IsNullOrWhiteSpace(biome))
			{
				record.Biome = biome;
				if (tfaCurrentBiomeId != null)
				{
					record.TfaCurrentBiomeId = tfaCurrentBiomeId;
				}
			}
		}

		private static bool IsRunResumeCandidate(ClimbRecord? record, string photonRoomName, string runId)
		{
			if (record != null && record.NetworkMode == "Multiplayer" && string.Equals(record.PhotonRoomName, photonRoomName, StringComparison.Ordinal) && string.Equals(record.RunId, runId, StringComparison.OrdinalIgnoreCase))
			{
				if (!(record.Outcome == "InProgress"))
				{
					return record.Outcome == "Abandoned";
				}
				return true;
			}
			return false;
		}

		private static void RefreshResumedRecord(ClimbRecord record, ClimbRecord currentRecord, float? elapsedSeconds)
		{
			string runId = record.RunId;
			string startedAtUtc = record.StartedAtUtc;
			bool runIdConfirmed = record.RunIdConfirmed || currentRecord.RunIdConfirmed;
			float currentHeightMeters = record.CurrentHeightMeters;
			int playerCount = record.PlayerCount;
			IReadOnlyList<MapBiomeInfo> mapBiomes = record.MapBiomes;
			List<MapBiomeInfo> list = CopyMapBiomes(currentRecord.MapBiomes);
			List<int> list2 = CopyMapSegmentBiomeIndices(currentRecord.MapSegmentBiomeIndices);
			IReadOnlyList<int> mapSegmentBiomeIndices = record.MapSegmentBiomeIndices;
			IReadOnlyList<ClimbPlayerInfo> otherPlayers = record.OtherPlayers;
			bool flag = SameTfaRoute(mapBiomes, list);
			bool flag2 = record.TrueFinalAscentEnabled && currentRecord.TrueFinalAscentEnabled && !currentRecord.TFAMapSeed.HasValue && currentRecord.MapBiomes.Count == 0;
			if (record.TrueFinalAscentEnabled || currentRecord.TrueFinalAscentEnabled)
			{
				flag = record.TrueFinalAscentEnabled && currentRecord.TrueFinalAscentEnabled && record.TFAMapSeed.HasValue && record.TFAMapSeed == currentRecord.TFAMapSeed && SameTfaRoute(mapBiomes, list);
				if (flag)
				{
					PreserveTfaTerminalEntries(mapBiomes, list, list2);
				}
			}
			else if (flag)
			{
				PreserveTfaTerminalEntries(mapBiomes, list, list2);
			}
			bool flag3 = flag || flag2;
			bool flag4 = flag3;
			if (flag4)
			{
				string segmentTimingMapKey = currentRecord.SegmentTimingMapKey;
				bool flag5 = (((segmentTimingMapKey != null && segmentTimingMapKey.Length == 0) || segmentTimingMapKey == "pending") ? true : false);
				flag4 = flag5 || record.SegmentTimingMapKey.Length == 0 || record.SegmentTimingMapKey == currentRecord.SegmentTimingMapKey;
			}
			bool flag6 = flag4;
			record.SegmentTimings = (flag6 ? ClimbSegmentTimer.Merge(record.SegmentTimings, currentRecord.SegmentTimings) : ClimbSegmentTimer.Copy(currentRecord.SegmentTimings));
			bool flag7 = !flag6;
			bool flag8 = flag7;
			if (!flag8)
			{
				string segmentTimingMapKey = currentRecord.SegmentTimingMapKey;
				bool flag5 = (((segmentTimingMapKey != null && segmentTimingMapKey.Length == 0) || segmentTimingMapKey == "pending") ? true : false);
				flag8 = !flag5;
			}
			if (flag8)
			{
				record.SegmentTimingMapKey = currentRecord.SegmentTimingMapKey;
			}
			record.RunId = runId;
			record.RunIdConfirmed = runIdConfirmed;
			record.StartedAtUtc = startedAtUtc;
			record.EndedAtUtc = "";
			record.Outcome = "InProgress";
			record.DurationSeconds = elapsedSeconds ?? record.DurationSeconds;
			record.CurrentHeightMeters = Math.Max(currentHeightMeters, currentRecord.CurrentHeightMeters);
			record.Ascent = currentRecord.Ascent;
			record.PlayerCount = Math.Max(playerCount, currentRecord.PlayerCount);
			record.IsCustomRun = currentRecord.IsCustomRun;
			record.IsMiniRun = currentRecord.IsMiniRun;
			record.Level = currentRecord.Level;
			if (!flag2)
			{
				record.Biome = currentRecord.Biome;
				record.TfaCurrentBiomeId = currentRecord.TfaCurrentBiomeId;
			}
			record.MapBiomes = (flag2 ? CopyMapBiomes(mapBiomes) : (flag ? MergeResumedMapBiomes(mapBiomes, list) : list));
			record.MapSegmentBiomeIndices = ((flag && IsValidMapSegmentBiomeMapping(mapSegmentBiomeIndices, mapBiomes.Count) && (currentRecord.MapSegmentBiomeIndices.Count == 0 || mapSegmentBiomeIndices.Count == currentRecord.MapSegmentBiomeIndices.Count)) ? CopyMapSegmentBiomeIndices(mapSegmentBiomeIndices) : list2);
			record.TerrainRandomiserEnabled = false;
			record.TerrainRandomiserSeed = -1;
			record.TerrainRandomiserMapSettingsBrotliBase64 = "";
			record.PLLMapSeed = currentRecord.PLLMapSeed;
			record.TrueFinalAscentEnabled = currentRecord.TrueFinalAscentEnabled;
			record.TFAApocalypseEnabled |= currentRecord.TFAApocalypseEnabled;
			if (!flag2)
			{
				record.TFAMapSeed = currentRecord.TFAMapSeed;
			}
			record.NetworkMode = currentRecord.NetworkMode;
			record.PhotonRoomName = currentRecord.PhotonRoomName;
			record.OtherPlayers = CopyPlayers(otherPlayers);
			MergePlayers(record.OtherPlayers, currentRecord.OtherPlayers);
		}

		private static void UpdateNetworkState(ClimbRecord record, string networkMode, string photonRoomName)
		{
			if (!string.IsNullOrWhiteSpace(networkMode))
			{
				record.NetworkMode = networkMode;
				record.PhotonRoomName = ((networkMode == "Multiplayer") ? photonRoomName : "");
			}
		}

		internal void RecoverInterrupted()
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord != null)
			{
				FinalizeActive("Abandoned", activeRecord.DurationSeconds);
			}
		}

		private void FinalizeActive(string outcome, float durationSeconds)
		{
			ClimbRecord activeRecord = _data.ActiveRecord;
			if (activeRecord == null)
			{
				return;
			}
			if (outcome == "Abandoned")
			{
				foreach (ClimbRecord record in _data.Records)
				{
					if (string.Equals(record.RunId, activeRecord.RunId, StringComparison.OrdinalIgnoreCase) && IsCompletedOutcome(record.Outcome))
					{
						_data.ActiveRecord = null;
						Save(flushToDisk: true);
						return;
					}
				}
			}
			DateTimeOffset utcNow = DateTimeOffset.UtcNow;
			activeRecord.Outcome = outcome;
			ClimbSegmentTimer.Freeze(activeRecord.SegmentTimings, (outcome == "Summited") ? "RunEnded" : outcome);
			activeRecord.DurationSeconds = durationSeconds;
			activeRecord.EndedAtUtc = utcNow.ToString("O", CultureInfo.InvariantCulture);
			_data.Records.RemoveAll((ClimbRecord record) => string.Equals(record.RunId, activeRecord.RunId, StringComparison.OrdinalIgnoreCase));
			_data.Records.Add(activeRecord);
			_data.ActiveRecord = null;
			Save(flushToDisk: true);
		}

		private static bool IsCompletedOutcome(string outcome)
		{
			if (!(outcome == "Summited"))
			{
				return outcome == "Failed";
			}
			return true;
		}

		private static ClimbHistoryData Deserialize(string json)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			JObject val = JsonConvert.DeserializeObject<JObject>(json, JsonSettings) ?? throw new JsonSerializationException("Climb history must be a JSON object.");
			JToken val2 = default(JToken);
			if (!val.TryGetValue("Records", StringComparison.OrdinalIgnoreCase, ref val2) || !(val2 is JArray))
			{
				throw new JsonSerializationException("Climb history must contain a Records array.");
			}
			ClimbHistoryData climbHistoryData = ((JToken)val).ToObject<ClimbHistoryData>(JsonSerializer.Create(JsonSettings));
			if (climbHistoryData == null || climbHistoryData.Records == null || climbHistoryData.Records.Exists((ClimbRecord record) => record == null))
			{
				throw new JsonSerializationException("Climb history contains invalid records.");
			}
			climbHistoryData.SchemaVersion = 16;
			NormalizeRecords(climbHistoryData.Records);
			if (climbHistoryData.ActiveRecord != null)
			{
				NormalizeRecord(climbHistoryData.ActiveRecord);
			}
			return climbHistoryData;
		}

		private void Save(bool flushToDisk = false)
		{
			//IL_0023: Expected O, but got Unknown
			try
			{
				string json = JsonConvert.SerializeObject((object)_data, (Formatting)0, JsonSettings);
				_storage.Save(json, flushToDisk);
			}
			catch (JsonException ex)
			{
				JsonException arg = ex;
				Plugin.Logger.LogError((object)$"Failed to serialize climb history: {arg}");
			}
		}

		private static List<MapBiomeInfo> CopyMapBiomes(IReadOnlyList<MapBiomeInfo> mapBiomes)
		{
			List<MapBiomeInfo> list = new List<MapBiomeInfo>(mapBiomes.Count);
			foreach (MapBiomeInfo mapBiome in mapBiomes)
			{
				list.Add(CopyMapBiome(mapBiome));
			}
			return list;
		}

		private static MapBiomeInfo CopyMapBiome(MapBiomeInfo biome)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return new MapBiomeInfo
			{
				BiomeType = biome.BiomeType,
				Variant = biome.Variant,
				OpenTomb = biome.OpenTomb,
				TitleKey = biome.TitleKey,
				TfaSegmentIndex = biome.TfaSegmentIndex,
				TfaChainIndex = biome.TfaChainIndex,
				TfaBiomeId = biome.TfaBiomeId,
				TfaBiomeNames = CopyTfaBiomeNames(biome.TfaBiomeNames),
				IsRouteTerminal = biome.IsRouteTerminal,
				TfaScalePercent = biome.TfaScalePercent,
				TfaScaleAxis = biome.TfaScaleAxis
			};
		}

		private static List<MapBiomeInfo> MergeResumedMapBiomes(IReadOnlyList<MapBiomeInfo> existingMapBiomes, IReadOnlyList<MapBiomeInfo> currentMapBiomes)
		{
			List<MapBiomeInfo> list = CopyMapBiomes(currentMapBiomes);
			for (int i = 0; i < existingMapBiomes.Count; i++)
			{
				MapBiomeInfo mapBiomeInfo = existingMapBiomes[i];
				MapBiomeInfo mapBiomeInfo2 = list[i];
				if (!string.IsNullOrWhiteSpace(mapBiomeInfo.Variant))
				{
					mapBiomeInfo2.Variant = mapBiomeInfo.Variant;
				}
				if (mapBiomeInfo.OpenTomb.HasValue)
				{
					mapBiomeInfo2.OpenTomb = mapBiomeInfo.OpenTomb;
				}
				MergeTfaBiomeNames(mapBiomeInfo, mapBiomeInfo2);
				PreserveTfaScale(mapBiomeInfo, mapBiomeInfo2);
			}
			return list;
		}

		private static bool SameMapBiomeRoute(IReadOnlyList<MapBiomeInfo> first, IReadOnlyList<MapBiomeInfo> second)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (first.Count != second.Count)
			{
				return false;
			}
			for (int i = 0; i < first.Count; i++)
			{
				if (first[i].BiomeType != second[i].BiomeType || first[i].TitleKey != second[i].TitleKey || first[i].IsRouteTerminal != second[i].IsRouteTerminal || first[i].TfaBiomeId != second[i].TfaBiomeId || first[i].TfaSegmentIndex != second[i].TfaSegmentIndex || first[i].TfaChainIndex != second[i].TfaChainIndex || first[i].TfaScalePercent != second[i].TfaScalePercent || first[i].TfaScaleAxis != second[i].TfaScaleAxis)
				{
					return false;
				}
			}
			return true;
		}

		private static bool SameTfaRoute(IReadOnlyList<MapBiomeInfo> first, IReadOnlyList<MapBiomeInfo> second)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			int num = first.Count;
			int num2 = second.Count;
			while (num > 0 && IsTfaTerminalEntry(first[num - 1]))
			{
				num--;
			}
			while (num2 > 0 && IsTfaTerminalEntry(second[num2 - 1]))
			{
				num2--;
			}
			if (num == 0 || num != num2)
			{
				return false;
			}
			for (int i = 0; i < num; i++)
			{
				if (first[i].BiomeType != second[i].BiomeType || first[i].TitleKey != second[i].TitleKey || first[i].TfaBiomeId != second[i].TfaBiomeId || first[i].TfaSegmentIndex != second[i].TfaSegmentIndex || first[i].TfaChainIndex != second[i].TfaChainIndex || ConflictingTfaScale(first[i], second[i]))
				{
					return false;
				}
			}
			return true;
		}

		private static bool ConflictingTfaScale(MapBiomeInfo first, MapBiomeInfo second)
		{
			if (first.TfaScalePercent.HasValue && first.TfaScaleAxis.HasValue && second.TfaScalePercent.HasValue && second.TfaScaleAxis.HasValue)
			{
				if (first.TfaScalePercent == second.TfaScalePercent)
				{
					return first.TfaScaleAxis != second.TfaScaleAxis;
				}
				return true;
			}
			return false;
		}

		private static void PreserveTfaScale(MapBiomeInfo existing, MapBiomeInfo current)
		{
			if (!current.TfaScalePercent.HasValue || !current.TfaScaleAxis.HasValue)
			{
				current.TfaScalePercent = existing.TfaScalePercent;
				current.TfaScaleAxis = existing.TfaScaleAxis;
			}
		}

		private static bool IsTfaTerminalEntry(MapBiomeInfo biome)
		{
			return biome.IsRouteTerminal;
		}

		private static void PreserveTfaTerminalEntries(IReadOnlyList<MapBiomeInfo> existing, List<MapBiomeInfo> current, List<int>? mapping = null)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Invalid comparison between Unknown and I4
			foreach (MapBiomeInfo biome in existing)
			{
				if (!IsTfaTerminalEntry(biome) || current.Exists((MapBiomeInfo mapBiomeInfo) => IsTfaTerminalEntry(mapBiomeInfo) && mapBiomeInfo.BiomeType == biome.BiomeType))
				{
					continue;
				}
				MapBiomeInfo item = CopyMapBiome(biome);
				int num = current.FindIndex((MapBiomeInfo mapBiomeInfo) => IsTfaTerminalEntry(mapBiomeInfo) && (int)mapBiomeInfo.BiomeType == 17);
				if ((int)biome.BiomeType == 5 && num >= 0)
				{
					current.Insert(num, item);
					if (mapping == null)
					{
						continue;
					}
					for (int num2 = 0; num2 < mapping.Count; num2++)
					{
						if (mapping[num2] >= num)
						{
							mapping[num2]++;
						}
					}
				}
				else
				{
					current.Add(item);
				}
			}
		}

		private static Dictionary<string, string> CopyTfaBiomeNames(IReadOnlyDictionary<string, string>? names)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			if (names == null)
			{
				return dictionary;
			}
			string[] array = new string[2] { "en", "cn" };
			foreach (string key in array)
			{
				if (names.TryGetValue(key, out string value) && !string.IsNullOrWhiteSpace(value))
				{
					dictionary.Add(key, value);
				}
			}
			return dictionary;
		}

		private static void MergeTfaBiomeNames(MapBiomeInfo existing, MapBiomeInfo current)
		{
			foreach (KeyValuePair<string, string> tfaBiomeName in existing.TfaBiomeNames)
			{
				current.TfaBiomeNames.TryAdd(tfaBiomeName.Key, tfaBiomeName.Value);
			}
		}

		private static bool SameTfaBiomeNames(MapBiomeInfo first, MapBiomeInfo second)
		{
			if (first.TfaBiomeNames.Count != second.TfaBiomeNames.Count)
			{
				return false;
			}
			foreach (KeyValuePair<string, string> tfaBiomeName in first.TfaBiomeNames)
			{
				if (!second.TfaBiomeNames.TryGetValue(tfaBiomeName.Key, out string value) || tfaBiomeName.Value != value)
				{
					return false;
				}
			}
			return true;
		}

		private static bool IsValidMapSegmentBiomeMapping(IReadOnlyList<int> mapping, int mapBiomeCount)
		{
			if (mapping.Count == 0 || mapBiomeCount == 0)
			{
				return false;
			}
			bool result = false;
			foreach (int item in mapping)
			{
				if (item < -1 || item >= mapBiomeCount)
				{
					return false;
				}
				if (item >= 0)
				{
					result = true;
				}
			}
			return result;
		}

		private static List<int> CopyMapSegmentBiomeIndices(IReadOnlyList<int> mapping)
		{
			return new List<int>(mapping);
		}

		private static List<ClimbPlayerInfo> CopyPlayers(IReadOnlyList<ClimbPlayerInfo> players)
		{
			List<ClimbPlayerInfo> list = new List<ClimbPlayerInfo>(players.Count);
			MergePlayers(list, players);
			foreach (ClimbPlayerInfo player in players)
			{
				if (PlayerIdentityCollector.TryNormalizeIdentity(player.Platform, player.PlatformUserId, out string platform, out string platformUserId) && PlayerIdentityCollector.IsLegacySteamIdentity(player) && PlayerIdentityCollector.IsValidSteamName(player.DisplayName))
				{
					int index = list.FindIndex((ClimbPlayerInfo item) => PlayerIdentityCollector.MatchesIdentity(item, platform, platformUserId));
					list[index].DisplayName = player.DisplayName;
				}
			}
			return list;
		}

		private static bool MergePlayers(List<ClimbPlayerInfo> activeRecordPlayers, IReadOnlyList<ClimbPlayerInfo> observedPlayers)
		{
			bool result = false;
			foreach (ClimbPlayerInfo observedPlayer in observedPlayers)
			{
				if (PlayerIdentityCollector.TryNormalizeIdentity(observedPlayer.Platform, observedPlayer.PlatformUserId, out string platform, out string platformUserId))
				{
					string validDisplayName = PlayerIdentityCollector.GetValidDisplayName(observedPlayer);
					ClimbPlayerInfo climbPlayerInfo = activeRecordPlayers.Find((ClimbPlayerInfo player) => PlayerIdentityCollector.MatchesIdentity(player, platform, platformUserId));
					if (climbPlayerInfo == null)
					{
						activeRecordPlayers.Add(new ClimbPlayerInfo
						{
							Platform = platform,
							PlatformUserId = platformUserId,
							DisplayName = validDisplayName
						});
						result = true;
					}
					else if (validDisplayName.Length > 0 && !string.Equals(climbPlayerInfo.DisplayName, validDisplayName, StringComparison.Ordinal))
					{
						climbPlayerInfo.DisplayName = validDisplayName;
						result = true;
					}
				}
			}
			return result;
		}

		private static void NormalizeRecords(List<ClimbRecord> records)
		{
			foreach (ClimbRecord record in records)
			{
				NormalizeRecord(record);
			}
		}

		private static void NormalizeRecord(ClimbRecord record)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Invalid comparison between Unknown and I4
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Invalid comparison between Unknown and I4
			ClimbRecord climbRecord = record;
			if (climbRecord.TfaCurrentBiomeId == null)
			{
				string text = (climbRecord.TfaCurrentBiomeId = "");
			}
			climbRecord = record;
			if (climbRecord.SegmentTimingMapKey == null)
			{
				string text = (climbRecord.SegmentTimingMapKey = "");
			}
			climbRecord = record;
			if (climbRecord.MapBiomes == null)
			{
				List<MapBiomeInfo> list = (climbRecord.MapBiomes = new List<MapBiomeInfo>());
			}
			foreach (MapBiomeInfo mapBiome in record.MapBiomes)
			{
				MapBiomeInfo mapBiomeInfo = mapBiome;
				if (mapBiomeInfo.TitleKey == null)
				{
					string text = (mapBiomeInfo.TitleKey = "");
				}
				mapBiomeInfo = mapBiome;
				if (mapBiomeInfo.TfaBiomeId == null)
				{
					string text = (mapBiomeInfo.TfaBiomeId = "");
				}
				mapBiome.TfaBiomeNames = CopyTfaBiomeNames(mapBiome.TfaBiomeNames);
				bool flag = record.TrueFinalAscentEnabled && !mapBiome.TfaSegmentIndex.HasValue;
				bool flag2 = flag;
				if (flag2)
				{
					BiomeType biomeType = mapBiome.BiomeType;
					bool flag3 = (((int)biomeType == 5 || (int)biomeType == 17) ? true : false);
					flag2 = flag3;
				}
				if (flag2)
				{
					mapBiome.IsRouteTerminal = true;
				}
			}
			climbRecord = record;
			if (climbRecord.MapSegmentBiomeIndices == null)
			{
				List<int> list3 = (climbRecord.MapSegmentBiomeIndices = new List<int>());
			}
			record.OtherPlayers = ((record.OtherPlayers != null) ? CopyPlayers(record.OtherPlayers) : new List<ClimbPlayerInfo>());
		}
	}
	internal sealed class ClimbHistoryPage : UIPage, IHaveParentPage
	{
		internal UIPage ParentPage { get; set; }

		internal Action? OnOpened { get; set; }

		internal Action? OnClosing { get; set; }

		internal Func<UIPage>? ResolveBackTarget { get; set; }

		public override void OnPageEnter()
		{
			((UIPage)this).OnPageEnter();
			OnOpened?.Invoke();
		}

		public override void OnPageExit()
		{
			OnClosing?.Invoke();
			((PageBase)this).OnPageExit();
		}

		private void OnDisable()
		{
			OnClosing?.Invoke();
		}

		public (UIPage, PageTransistion) GetParentPage()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (ResolveBackTarget != null)
			{
				return (ResolveBackTarget(), (PageTransistion)new SetActivePageTransistion());
			}
			return (ParentPage, (PageTransistion)new SetActivePageTransistion());
		}
	}
	internal sealed class ClimbHistoryDetailsPage : UIPage, IHaveParentPage
	{
		internal UIPage ParentPage { get; set; }

		internal Action? OnOpened { get; set; }

		internal Action? OnClosing { get; set; }

		public override void OnPageEnter()
		{
			((UIPage)this).OnPageEnter();
			OnOpened?.Invoke();
		}

		public override void OnPageExit()
		{
			OnClosing?.Invoke();
			((PageBase)this).OnPageExit();
		}

		public (UIPage, PageTransistion) GetParentPage()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			return (ParentPage, (PageTransistion)new SetActivePageTransistion());
		}
	}
	internal sealed class ClimbHistoryModalPage : UIPage, IHaveParentPage
	{
		internal UIPage ParentPage { get; set; }

		internal Action? OnOpened { get; set; }

		internal Action? OnClosing { get; set; }

		public override void OnPageEnter()
		{
			((UIPage)this).OnPageEnter();
			OnOpened?.Invoke();
		}

		public override void OnPageExit()
		{
			OnClosing?.Invoke();
			((PageBase)this).OnPageExit();
		}

		private void OnDisable()
		{
			OnClosing?.Invoke();
		}

		public (UIPage, PageTransistion) GetParentPage()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			return (ParentPage, (PageTransistion)new SetActivePageTransistion());
		}
	}
	internal sealed class OverlayPageTransistion : PageTransistion
	{
		public override void Transistion(PageBase oldSubPage, PageBase newSubPage)
		{
			oldSubPage.OnPageExit();
			((Component)newSubPage).gameObject.SetActive(true);
			newSubPage.OnPageEnter();
			newSubPage.OnPageEntered();
		}
	}
	internal sealed class ClimbHistoryButton
	{
		private readonly Image? _panel;

		private readonly Image? _borderTop;

		private readonly Image? _borderBottom;

		internal GameObject GameObject { get; }

		internal RectTransform RectTransform { get; }

		internal Button Button { get; }

		internal TextMeshProUGUI Text { get; }

		private ClimbHistoryButton(GameObject gameObject)
		{
			GameObject = gameObject;
			RectTransform = gameObject.GetComponent<RectTransform>();
			Button = gameObject.GetComponent<Button>();
			Text = gameObject.GetComponentInChildren<TextMeshProUGUI>(true);
			Transform obj = gameObject.transform.Find("Panel");
			_panel = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null);
			Transform val = gameObject.transform.Find("Border");
			_borderTop = ((val != null) ? ((Component)val).GetComponent<Image>() : null);
			_borderBottom = (((Object)(object)val != (Object)null && val.GetSiblingIndex() + 1 < gameObject.transform.childCount) ? ((Component)gameObject.transform.GetChild(val.GetSiblingIndex() + 1)).GetComponent<Image>() : null);
		}

		internal static ClimbHistoryButton Create(GameObject template, string objectName, Transform parent)
		{
			GameObject val = Object.Instantiate<GameObject>(template, parent, false);
			((Object)val).name = objectName;
			LocalizedText componentInChildren = val.GetComponentInChildren<LocalizedText>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)componentInChildren);
			}
			ClimbHistoryButton climbHistoryButton = new ClimbHistoryButton(val);
			((UnityEventBase)climbHistoryButton.Button.onClick).RemoveAllListeners();
			return climbHistoryButton;
		}

		internal void SetText(string value)
		{
			((TMP_Text)Text).text = value;
		}

		internal void SetColor(Color color)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_panel != (Object)null)
			{
				((Graphic)_panel).color = color;
			}
			float num = default(float);
			float num2 = default(float);
			float num3 = default(float);
			Color.RGBToHSV(color, ref num, ref num2, ref num3);
			float num4 = ((num3 > 0.5f) ? Mathf.Clamp01(num3 - 0.2f) : Mathf.Clamp01(num3 + 0.2f));
			Color color2 = Color.HSVToRGB(num, num2, num4);
			if ((Object)(object)_borderTop != (Object)null)
			{
				((Graphic)_borderTop).color = color2;
			}
			if ((Object)(object)_borderBottom != (Object)null)
			{
				((Graphic)_borderBottom).color = color2;
			}
		}
	}
	internal sealed class ClimbHistoryScrollSelection : MonoBehaviour, ISelectHandler, IEventSystemHandler
	{
		internal ScrollRect? Scroll { get; set; }

		internal RectTransform? Row { get; set; }

		public void OnSelect(BaseEventData eventData)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_006d: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: 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_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Scroll == (Object)null || (Object)(object)Row == (Object)null || (Object)(object)Scroll.content == (Object)null || (Object)(object)Scroll.viewport == (Object)null)
			{
				return;
			}
			Rect rect = Scroll.viewport.rect;
			Bounds val = RectTransformUtility.CalculateRelativeRectTransformBounds((Transform)(object)Scroll.viewport, (Transform)(object)Row);
			float num;
			if (((Bounds)(ref val)).size.y > ((Rect)(ref rect)).height || ((Bounds)(ref val)).max.y > ((Rect)(ref rect)).yMax)
			{
				num = ((Rect)(ref rect)).yMax - ((Bounds)(ref val)).max.y;
			}
			else
			{
				if (!(((Bounds)(ref val)).min.y < ((Rect)(ref rect)).yMin))
				{
					return;
				}
				num = ((Rect)(ref rect)).yMin - ((Bounds)(ref val)).min.y;
			}
			Scroll.StopMovement();
			Vector2 anchoredPosition = Scroll.content.anchoredPosition;
			float num2 = anchoredPosition.y + num;
			Rect rect2 = Scroll.content.rect;
			anchoredPosition.y = Mathf.Clamp(num2, 0f, Mathf.Max(0f, ((Rect)(ref rect2)).height - ((Rect)(ref rect)).height));
			Scroll.content.anchoredPosition = anchoredPosition;
		}
	}
	internal sealed class ClimbHistoryStorage
	{
		private enum ReadStatus
		{
			Missing,
			Valid,
			Invalid,
			Unavailable
		}

		private readonly string _path;

		private readonly Func<string, ClimbHistoryData> _deserialize;

		private bool _archiveMain;

		private bool _archiveBackup;

		private bool _readUnavailable;

		internal ClimbHistoryStorage(string path, Func<string, ClimbHistoryData> deserialize)
		{
			_path = path;
			_deserialize = deserialize;
		}

		internal ClimbHistoryData Load()
		{
			ClimbHistoryData data;
			string json;
			ReadStatus readStatus = Read(_path, out data, out json);
			if (readStatus == ReadStatus.Valid)
			{
				return data;
			}
			ClimbHistoryData data2;
			string json2;
			ReadStatus readStatus2 = Read(_path + ".bak", out data2, out json2);
			_archiveMain = readStatus == ReadStatus.Invalid;
			_archiveBackup = readStatus2 == ReadStatus.Invalid;
			_readUnavailable = readStatus == ReadStatus.Unavailable || readStatus2 == ReadStatus.Unavailable;
			if (_readUnavailable)
			{
				Plugin.Logger.LogError((object)"Climb history could not be read; existing files will not be overwritten this session.");
				return data2 ?? new ClimbHistoryData();
			}
			if (readStatus2 == ReadStatus.Valid)
			{
				if (Save(json2, flushToDisk: true))
				{
					Plugin.Logger.LogWarning((object)"Restored climb history from its backup.");
				}
				return data2;
			}
			if (_archiveMain || _archiveBackup)
			{
				try
				{
					ArchiveInvalidFiles();
					Plugin.Logger.LogError((object)"No readable climb history or backup remains; preserved the invalid files and started a new history.");
				}
				catch (Exception ex) when (IsFileException(ex))
				{
					Plugin.Logger.LogError((object)$"Failed to preserve invalid climb history files: {ex}");
				}
			}
			return new ClimbHistoryData();
		}

		internal bool Save(string json, bool flushToDisk)
		{
			if (_readUnavailable)
			{
				return false;
			}
			try
			{
				string directoryName = Path.GetDirectoryName(_path);
				if (!string.IsNullOrEmpty(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				ArchiveInvalidFiles();
				string text = _path + ".tmp";
				byte[] bytes = Encoding.UTF8.GetBytes(json);
				using (FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None))
				{
					fileStream.Write(bytes, 0, bytes.Length);
					fileStream.Flush(flushToDisk);
				}
				if (File.Exists(_path))
				{
					File.Replace(text, _path, _path + ".bak");
				}
				else
				{
					File.Move(text, _path);
				}
				return true;
			}
			catch (Exception ex) when (IsFileException(ex))
			{
				Plugin.Logger.LogError((object)$"Failed to save climb history: {ex}");
				return false;
			}
		}

		private ReadStatus Read(string path, out ClimbHistoryData? data, out string? json)
		{
			//IL_002c: Expected O, but got Unknown
			data = null;
			json = null;
			try
			{
				json = File.ReadAllText(path);
				data = _deserialize(json);
				return ReadStatus.Valid;
			}
			catch (FileNotFoundException)
			{
				return ReadStatus.Missing;
			}
			catch (DirectoryNotFoundException)
			{
				return ReadStatus.Missing;
			}
			catch (JsonException ex3)
			{
				JsonException ex4 = ex3;
				Plugin.Logger.LogWarning((object)("Invalid climb history file '" + path + "': " + ((Exception)(object)ex4).Message));
				return ReadStatus.Invalid;
			}
			catch (Exception ex5) when (IsFileException(ex5))
			{
				Plugin.Logger.LogError((object)$"Failed to read climb history file '{path}': {ex5}");
				return ReadStatus.Unavailable;
			}
		}

		private void ArchiveInvalidFiles()
		{
			if (_archiveMain)
			{
				Archive(_path);
				_archiveMain = false;
			}
			if (_archiveBackup)
			{
				Archive(_path + ".bak");
				_archiveBackup = false;
			}
		}

		private static void Archive(string path)
		{
			if (File.Exists(path))
			{
				string text = path + ".load-failed." + DateTimeOffset.UtcNow.ToString("yyyyMMddTHHmmssfffZ", CultureInfo.InvariantCulture);
				string text2 = text;
				int num = 1;
				while (File.Exists(text2))
				{
					text2 = text + "_" + num.ToString(CultureInfo.InvariantCulture);
					num++;
				}
				File.Move(path, text2);
				Plugin.Logger.LogWarning((object)("Preserved invalid climb history at '" + text2 + "'."));
			}
		}

		private static bool IsFileException(Exception exception)
		{
			if (exception is IOException || exception is UnauthorizedAccessException || exception is NotSupportedException)
			{
				return true;
			}
			return false;
		}
	}
	internal static class ClimbHistoryUi
	{
		private sealed class RecordRowView
		{
			internal string RunId { get; }

			internal GameObject GameObject { get; }

			internal ClimbHistoryButton DeleteButton { get; }

			internal ClimbHistoryButton? DetailsButton { get; }

			internal RecordRowView(string runId, GameObject gameObject, ClimbHistoryButton deleteButton, ClimbHistoryButton? detailsButton)
			{
				RunId = runId;
				GameObject = gameObject;
				DeleteButton = deleteButton;
				DetailsButton = detailsButton;
			}
		}

		private enum RowAction
		{
			Back,
			Details,
			Delete,
			StatusFilter,
			MapFilter,
			ResetFilters,
			BulkDelete,
			ExitPlayerQuery,
			FellowPlayers,
			PlayerProfile
		}

		private sealed class BrowseState
		{
			internal int SceneHandle { get; init; }

			internal string? AnchorRunId { get; init; }

			internal float AnchorOffset { get; init; }

			internal List<string> RecordOrder { get; init; } = new List<string>();

			internal string? FocusRunId { get; init; }

			internal RowAction FocusAction { get; init; }
		}

		private enum FellowSort
		{
			MostRecent,
			RecordCount
		}

		private enum FellowFocus
		{
			Search,
			Sort,
			Records,
			PlayerDetails,
			Scrollbar,
			Back
		}

		private sealed class FellowSummary
		{
			internal string Platform { get; init; } = "";

			internal string UserId { get; init; } = "";

			internal string DisplayPlatform { get; init; } = "";

			internal string DisplayName { get; set; } = "";

			internal DateTimeOffset NameDate { get; set; } = DateTimeOffset.MinValue;

			internal DateTimeOffset LatestDate { get; set; } = DateTimeOffset.MinValue;

			internal HashSet<string> Names { get; } = new HashSet<string>(StringComparer.Ordinal);

			internal int Count { get; set; }

			internal string Key => Platform + ":" + UserId;

			internal PlayerQuery ToQuery()
			{
				return new PlayerQuery
				{
					Platform = Platform,
					UserId = UserId,
					DisplayPlatform = DisplayPlatform,
					DisplayName = DisplayName
				};
			}
		}

		private sealed class FellowRow
		{
			internal string Key { get; init; } = "";

			internal RectTransform Rect { get; init; }

			internal ClimbHistoryButton Button { get; init; }

			internal ClimbHistoryButton DetailsButton { get; init; }
		}

		private sealed class FellowBrowseState
		{
			internal int SceneHandle { get; init; }

			internal string? Anchor { get; init; }

			internal float Offset { get; init; }

			internal List<string> Order { get; init; } = new List<string>();

			internal string? FocusKey { get; init; }

			internal FellowFocus Focus { get; init; }
		}

		private enum MapSource
		{
			All,
			Vanilla,
			PLL,
			TFA,
			TerrainRandomiser
		}

		private enum ModalKind
		{
			None,
			ConfirmDelete,
			DeleteFailed
		}

		private sealed class PlayerQuery
		{
			internal string Platform { get; init; } = "";

			internal string UserId { get; init; } = "";

			internal string DisplayName { get; init; } = "";

			internal string DisplayPlatform { get; init; } = "";
		}

		private sealed class PlayerQueryContext
		{
			internal int SceneHandle { get; init; }

			internal string? Outcome { get; init; }

			internal MapSource Map { get; init; }

			internal BrowseState Browse { get; init; }

			internal bool FromFellowPlayers { get; init; }
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static Action <0>__OnLanguageChanged;

			public static Action <1>__CaptureBrowseState;

			public static Func<UIPage> <2>__ResolveHistoryBackTarget;

			public static Action <3>__OnDetailsPageClosing;

			public static UnityAction <4>__CloseDetailsPage;

			public static UnityAction <5>__LoadSelectedMapSettings;

			public static UnityAction <6>__SaveSelectedMapSettings;

			public static Func<ClimbRecord, bool> <7>__MatchesFilters;

			public static Func<string, string> <8>__LocalizeBiomeTextId;

			public static Func<UIPage> <9>__ResolveFellowPlayersBackTarget;

			public static Func<string, string> <10>__OutcomeFilterName;

			public static Func<MapSource, string> <11>__MapFilterName;

			public static Action <12>__ResetFilters;

			public static Action <13>__OpenFellowPlayersPage;

			public static Action <14>__OpenDeleteConfirmation;

			public static Func<ClimbRecord, bool> <15>__CanBulkDelete;

			public static Action <16>__OnModalPageClosing;

			public static Action <17>__CloseModalPage;

			public static Action <18>__ConfirmBulkDelete;

			public static Func<UIPage> <19>__ResolvePlayerProfileBackTarget;

			public static Action <20>__OnPlayerProfileClosing;

			public static UnityAction<Scene, Scene> <21>__OnPlayerProfileSceneChanged;

			public static DispatchDelegate<PersonaStateChange_t> <22>__OnProfilePersonaChanged;

			public static DispatchDelegate<AvatarImageLoaded_t> <23>__OnProfileAvatarLoaded;

			public static DispatchDelegate<GameOverlayActivated_t> <24>__OnProfileOverlayChanged;

			public static Action <25>__ClosePlayerProfile;

			public static Action <26>__ExitPlayerQuery;
		}

		private static readonly List<RecordRowView> Rows = new List<RecordRowView>();

		private static readonly List<GameObject> DetailRouteRows = new List<GameObject>();

		private static readonly List<GameObject> DetailPlayerRows = new List<GameObject>();

		private static readonly Dictionary<string, RecordRowView> RowsByRunId = new Dictionary<string, RecordRowView>();

		private static bool _registered;

		private static bool _languageSubscribed;

		private static Transform? _pauseMenuParent;

		private static PauseMenuHandler? _pauseMenuHandler;

		private static PauseMenuMainPage? _parentPage;

		private static ClimbHistoryPage? _historyPage;

		private static ClimbHistoryDetailsPage? _detailsPage;

		private static CanvasGroup? _historyCanvasGroup;

		private static ClimbHistoryButton? _openButton;

		private static ClimbHistoryButton? _backButton;

		private static ClimbHistoryButton? _detailsCloseButton;

		private static ClimbHistoryButton? _detailsLoadButton;

		private static ClimbHistoryButton? _detailsSaveButton;

		private static RectTransform? _rowsContent;

		private static ScrollRect? _rowsScrollRect;

		private static RectTransform? _rowsDivider;

		private static RectTransform? _detailsRouteContent;

		private static ScrollRect? _detailsRouteScrollRect;

		private static RectTransform? _detailsPlayersContent;

		private static ScrollRect? _detailsPlayersScrollRect;

		private static TextMeshProUGUI? _titleText;

		private static TextMeshProUGUI? _summaryText;

		private static TextMeshProUGUI? _emptyText;

		private static TextMeshProUGUI? _detailsTitleText;

		private static TextMeshProUGUI? _detailsMetadataText;

		private static TextMeshProUGUI? _detailsRouteTitleText;

		private static TextMeshProUGUI? _detailsPlayersTitleText;

		private static TextMeshProUGUI? _detailsRouteEmptyText;

		private static TextMeshProUGUI? _detailsPlayersEmptyText;

		private static ClimbRecord? _selectedDetailsRecord;

		private static string? _pendingFocusRunId;

		private static BrowseState? _browseState;

		private static int _rowsSceneHandle = -1;

		private static TMP_FontAsset? _vanillaFont;

		private static GameObject? _menuButtonTemplate;

		private const float RowHeight = 132f;

		private const float RowActionRightPadding = 24f;

		private const float RowActionSpacing = 8f;

		private const float RowActionHeight = 44f;

		private const float RowDetailsActionWidth = 86f;

		private const float RowDeleteActionWidth = 92f;

		private const float RowActionFontSize = 20f;

		private const float PauseMenuButtonWidth = 277f;

		private static readonly IReadOnlyDictionary<BiomeType, string[]> BiomeTextIds = new Dictionary<BiomeType, string[]>
		{
			[(BiomeType)0] = new string[1] { "SHORE" },
			[(BiomeType)1] = new string[1] { "TROPICS" },
			[(BiomeType)2] = new string[1] { "ALPINE" },
			[(BiomeType)3] = new string[2] { "CALDERA", "THE KILN" },
			[(BiomeType)5] = new string[1] { "PEAK" },
			[(BiomeType)6] = new string[1] { "MESA" },
			[(BiomeType)7] = new string[1] { "ROOTS" },
			[(BiomeType)8] = new string[2] { "GLOOM", "THE CITADEL" },
			[(BiomeType)17] = new string[1] { "AREA_VOID" }
		};

		private static readonly HashSet<BiomeType> HasVariants = new HashSet<BiomeType>
		{
			(BiomeType)0,
			(BiomeType)1,
			(BiomeType)2,
			(BiomeType)6,
			(BiomeType)7
		};

		private static readonly IReadOnlyDictionary<BiomeType, IReadOnlyDictionary<string, string>> SimplifiedChineseVariantNames = new Dictionary<BiomeType, IReadOnlyDictionary<string, string>>
		{
			[(BiomeType)0] = new Dictionary<string, string>
			{
				["Default"] = "默认",
				["SnakeBeach"] = "蛇岩",
				["RedBeach"] = "赤沙",
				["BlueBeach"] = "蓝沙",
				["JellyHell"] = "水母地狱",
				["BlackSand"] = "黑沙"
			},
			[(BiomeType)1] = new Dictionary<string, string>
			{
				["Default"] = "默认",
				["Lava"] = "熔岩管",
				["Pillars"] = "巨柱",
				["Thorny"] = "巨棘藤",
				["Bombs"] = "爆菇",
				["Ivy"] = "紫毒藤",
				["SkyJungle"] = "浮岛"
			},
			[(BiomeType)7] = new Dictionary<string, string>
			{
				["Default"] = "默认",
				["CaveMania"] = "洞窟丛生",
				["DeepWater"] = "赤水孢泽",
				["BombBeetle"] = "爆菇甲虫",
				["DeepWoods"] = "幽深密林",
				["Clearcut"] = "皆伐菌原"
			},
			[(BiomeType)2] = new Dictionary<string, string>
			{
				["Default"] = "默认",
				["Lava"] = "熔岩管",
				["Spiky"] = "冰刺",
				["GeyserHell"] = "间歇泉地狱"
			},
			[(BiomeType)6] = new Dictionary<string, string>
			{
				["Default"] = "默认",
				["ScorpionsHell"] = "毒蝎地狱",
				["CactusHell"] = "峭壁仙人掌地狱",
				["CactusForest"] = "高原仙人掌林",
				["DynamiteHell"] = "炸药地狱",
				["TornadoHell"] = "龙卷风地狱",
				["TumblerHell"] = "风滚草地狱"
			}
		};

		private static ClimbHistoryPage? _fellowPlayersPage;

		private static TextMeshProUGUI? _fellowTitle;

		private static TextMeshProUGUI? _fellowSummaryText;

		private static TextMeshProUGUI? _fellowEmpty;

		private static TMP_InputField? _fellowSearchField;

		private static TMP_Dropdown? _fellowSortDropdown;

		private static ClimbHistoryButton? _fellowBackButton;

		private static RectTransform? _fellowPanel;

		private static RectTransform? _fellowContent;

		private static ScrollRect? _fellowScroll;

		private static readonly List<FellowRow> FellowRows = new List<FellowRow>();

		private static readonly List<FellowSummary> FellowSummaries = new List<FellowSummary>();

		private static string _fellowSearch = "";

		private static FellowSort _fellowSort;

		private static FellowBrowseState? _fellowBrowse;

		private static BrowseState? _fellowHistoryBrowse;

		private static int _fellowHistoryScene = -1;

		private static int _fellowRowsScene = -1;

		private static int _fellowEditEndedFrame = -1;

		private static bool _fellowFocusSearch;

		private static readonly string?[] OutcomeOptions = new string[5] { null, "InProgress", "Summited", "Failed", "Abandoned" };

		private static readonly MapSource[] MapOptions = new MapSource[5]
		{
			MapSource.All,
			MapSource.Vanilla,
			MapSource.PLL,
			MapSource.TFA,
			MapSource.TerrainRandomiser
		};

		private static readonly List<ClimbHistoryButton> ModalButtons = new List<ClimbHistoryButton>();

		private static string? _outcomeFilter;

		private static MapSource _mapFilter;

		private static TMP_Dropdown? _statusFilterDropdown;

		private static TMP_Dropdown? _mapFilterDropdown;

		private static ClimbHistoryButton? _resetFiltersButton;

		private static ClimbHistoryButton? _bulkDeleteButton;

		private static ClimbHistoryButton? _fellowPlayersButton;

		private static RectTransform? _filterPanel;

		private static ClimbHistoryModalPage? _modalPage;

		private static RectTransform? _modalPanel;

		private static TextMeshProUGUI? _modalTitle;

		private static TextMeshProUGUI? _modalBody;

		private static ScrollRect? _modalBodyScroll;

		private static ModalKind _modalKind;

		private static int _modalInitialFocusIndex;

		private static RowAction? _pendingToolbarFocus;

		private static bool _resetBrowseOnRefresh;

		private static bool _skipNextSnapshot;

		private static string[]? _pendingDeleteRunIds;

		private static string? _pendingDeleteOutcome;

		private static MapSource _pendingDeleteMap;

		private static PlayerQuery? _pendingDeletePlayer;

		private static ClimbHistoryPage? _playerProfilePage;

		private static RectTransform? _playerProfilePanel;

		private static TextMeshProUGUI? _playerProfileTitle;

		private static TextMeshProUGUI? _playerProfileBody;

		private static TextMeshProUGUI? _playerProfileAvatarText;

		private static RectTransform? _playerProfileAvatarRect;

		private static RawImage? _playerProfileAvatar;

		private static ScrollRect? _playerProfileScroll;

		private static ClimbHistoryButton? _playerProfileCloseButton;

		private static ClimbHistoryButton? _playerProfileSteamButton;

		private static ClimbHistoryButton? _playerProfileFriendButton;

		private static PlayerQuery? _profilePlayer;

		private static readonly List<string> ProfileRecordedNames = new List<string>();

		private static CanvasGroup? _profileSourceGroup;

		private static bool _profileSourceInteractable;

		private static bool _profileSourceRaycasts;

		private static CSteamID? _profileSteamId;

		private static string _profileSteamName = "";

		private static EFriendRelationship _profileRelationship;

		private static int _profileAvatarHandle;

		private static Texture2D? _profileAvatarTexture;

		private static Callback<PersonaStateChange_t>? _profilePersonaCallback;

		private static Callback<AvatarImageLoaded_t>? _profileAvatarCallback;

		private static Callback<GameOverlayActivated_t>? _profileOverlayCallback;

		private static bool _profileSteamOverlayActive;

		private static int _profileSteamOverlayClosedFrame = -1;

		private static readonly List<ClimbHistoryButton> DetailPlayerButtons = new List<ClimbHistoryButton>();

		private static PlayerQuery? _playerFilter;

		private static PlayerQueryContext? _playerQueryContext;

		private static BrowseState? _playerQueryReturnBrowse;

		private static bool _restorePlayerQueryBrowse;

		private static RectTransform? _playerQueryBanner;

		private static ClimbHistoryButton? _exitPlayerQueryButton;

		private static ClimbHistoryButton? _queryPlayerProfileButton;

		private static bool IsPlayerProfileOpen => _profilePlayer != null;

		private static bool SteamProfileAvailable
		{
			get
			{
				if ((Object)(object)SteamManager.Instance != (Object)null && SteamManager.Initialized && SteamAPI.IsSteamRunning())
				{
					return SteamUser.BLoggedOn();
				}
				return false;
			}
		}

		internal static void Register()
		{
			Plugin.Logger.LogDebug((object)($"Registering climb history UI. registered={_registered}, " + $"languageSubscribed={_languageSubscribed}, frame={Time.frameCount}."));
			if (!_registered)
			{
				_registered = true;
				Plugin.Logger.LogDebug((object)"Climb history pause menu builder registered.");
			}
			if (!_languageSubscribed)
			{
				LocalizedText.OnLangugageChanged = (Action)Delegate.Combine(LocalizedText.OnLangugageChanged, new Action(OnLanguageChanged));
				_languageSubscribed = true;
			}
		}

		internal static void Dispose()
		{
			ResetPlayerProfileUi();
			if (_languageSubscribed)
			{
				LocalizedText.OnLangugageChanged = (Action)Delegate.Remove(LocalizedText.OnLangugageChanged, new Action(OnLanguageChanged));
				_languageSubscribed = false;
			}
		}

		internal static void BuildPauseMenu(PauseMenuMainPage parentPage)
		{
			Transform transform = ((Component)parentPage).transform;
			if ((Object)(object)_pauseMenuParent == (Object)null || (Object)(object)_pauseMenuParent != (Object)(object)transform)
			{
				ResetBuiltUi();
			}
			_pauseMenuParent = transform;
			Plugin.Logger.LogDebug((object)("Building climb history pause menu. parent=" + DescribeTransform(transform) + ", " + $"existingPage={DescribeObject((Object?)(object)_historyPage)}, frame={Time.frameCount}."));
			_pauseMenuHandler = ((Component)transform).GetComponentInParent<PauseMenuHandler>();
			_parentPage = parentPage;
			Plugin.Logger.LogDebug((object)("Resolved pause menu references. handler=" + DescribeObject((Object?)(object)_pauseMenuHandler) + ", parentPage=" + DescribeObject((Object?)(object)_parentPage) + "."));
			if ((Object)(object)_pauseMenuHandler == (Object)null || (Object)(object)_parentPage == (Object)null)
			{
				Plugin.Logger.LogError((object)"Failed to create climb history page: pause menu references missing.");
				return;
			}
			BuildOpenButton();
			Plugin.Logger.LogDebug((object)("Finished building climb history pause menu entry. openButton=" + DescribeObject((Object?)(object)_openButton?.GameObject) + ", deferredPage=" + DescribeObject((Object?)(object)_historyPage) + "."));
		}

		private static bool EnsureHistoryPage()
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_historyPage != (Object)null && Object.op_Implicit((Object)(object)_historyPage))
			{
				Plugin.Logger.LogDebug((object)"Skipped climb history page build because it already exists.");
				return true;
			}
			if ((Object)(object)_parentPage == (Object)null || (Object)(object)_pauseMenuHandler == (Object)null)
			{
				Plugin.Logger.LogError((object)"Failed to create climb history page: pause menu references missing.");
				return false;
			}
			EnsureFonts();
			Plugin.Logger.LogDebug((object)("Creating deferred climb history child page. parentPage=" + DescribeObject((Object?)(object)_parentPage) + ", " + $"frame={Time.frameCount}."));
			GameObject val = new GameObject("ClimbInfoTracker_HistoryPage", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(((Component)_parentPage).transform.parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			_historyPage = val.AddComponent<ClimbHistoryPage>();
			_historyPage.ParentPage = (UIPage)(object)_parentPage;
			_historyCanvasGroup = val.AddComponent<CanvasGroup>();
			Plugin.Logger.LogDebug((object)("Created climb history child page. " + DescribePageState() + ", " + $"frame={Time.frameCount}."));
			CreatePageBackground(((Component)_historyPage).transform, new Color(0f, 0f, 0f, 0.87f));
			_historyPage.OnOpened = delegate
			{
				Plugin.Logger.LogDebug((object)("Climb history page OnOpen fired. " + DescribePageState() + ", " + $"frame={Time.frameCount}."));
				RefreshPage();
			};
			_historyPage.OnClosing = CaptureBrowseState;
			_historyPage.ResolveBackTarget = ResolveHistoryBackTarget;
			BuildHeader();
			BuildContent();
			BuildBackButton();
			BuildDetailsPage();
			BuildModalPage();
			BuildFellowPlayersPage();
			BuildPlayerProfilePage();
			Plugin.Logger.LogDebug((object)("Built climb history controls. title=" + DescribeObject((Object?)(object)_titleText) + ", rowsContent=" + DescribeRect(_rowsContent) + ", backButton=" + DescribeObject((Object?)(object)_backButton?.GameObject) + "."));
			((Component)_historyPage).gameObject.SetActive(false);
			Plugin.Logger.LogDebug((object)("Finished building climb history page and deactivated it. " + DescribePageState() + "."));
			return true;
		}

		private static void BuildHeader()
		{
			//IL_002e: 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_0058: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_historyPage == (Object)null))
			{
				RectTransform val = CreateRectObject("Header", ((Component)_historyPage).transform);
				val.anchorMin = new Vector2(0.5f, 1f);
				val.anchorMax = new Vector2(0.5f, 1f);
				val.anchoredPosition = new Vector2(0f, -32f);
				val.pivot = new Vector2(0.5f, 1f);
				val.sizeDelta = new Vector2(900f, 120f);
				_titleText = CreateText((Transform)(object)val, "Title", 54f, (TextAlignmentOptions)514);
				StretchToParent(((TMP_Text)_titleText).rectTransform);
				((TMP_Text)_titleText).enableAutoSizing = true;
				((TMP_Text)_titleText).fontSizeMin = 30f;
				((TMP_Text)_titleText).fontSizeMax = 54f;
			}
		}

		private static void BuildContent()
		{
			//IL_002e: 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_0058: 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_0082: 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_0150: 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_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_historyPage == (Object)null))
			{
				RectTransform val = CreateRectObject("Content", ((Component)_historyPage).transform);
				val.pivot = new Vector2(0.5f, 1f);
				val.anchorMin = new Vector2(0.5f, 1f);
				val.anchorMax = new Vector2(0.5f, 1f);
				val.anchoredPosition = new Vector2(0f, -140f);
				val.sizeDelta = new Vector2(1420f, 840f);
				RectTransform val2 = CreateRectObject("HistoryPanel", (Transform)(object)val);
				StretchToParent(val2);
				((Graphic)((Component)val2).gameObject.AddComponent<Image>()).color = new Color(0.11f, 0.09f, 0.08f, 0.76f);
				_summaryText = CreateText((Transform)(object)val2, "Summary", 32f, (TextAlignmentOptions)514);
				((TMP_Text)_summaryText).enableAutoSizing = true;
				((TMP_Text)_summaryText).fontSizeMin = 20f;
				((TMP_Text)_summaryText).fontSizeMax = 32f;
				ConfigureTopText(((TMP_Text)_summaryText).rectTransform, 90f, -24f, -90f, -70f);
				_filterPanel = val2;
				RectTransform val3 = (_rowsDivider = CreateRectObject("Divider", (Transform)(object)val2));
				val3.anchorMin = new Vector2(0f, 1f);
				val3.anchorMax = new Vector2(1f, 1f);
				val3.pivot = new Vector2(0.5f, 1f);
				val3.anchoredPosition = new Vector2(0f, -132f);
				val3.sizeDelta = new Vector2(-120f, 2f);
				((Graphic)((Component)val3).gameObject.AddComponent<Image>()).color = new Color(0.78f, 0.63f, 0.35f, 0.9f);
				ScrollRect val4 = (_rowsScrollRect = CreateScrollableContent((Transform)(object)val2, out _rowsContent));
				RectTransform component = ((Component)val4).GetComponent<RectTransform>();
				component.anchorMin = Vector2.zero;
				component.anchorMax = Vector2.one;
				component.offsetMin = new Vector2(56f, 84f);
				component.offsetMax = new Vector2(-80f, -156f);
				val4.verticalScrollbar = CreateRowsScrollbar(((Component)val2).transform);
				val4.verticalScrollbarVisibility = (ScrollbarVisibility)0;
				_emptyText = CreateText((Transform)(object)val2, "Empty", 30f, (TextAlignmentOptions)514);
				((Graphic)_emptyText).color = new Color(0.94f, 0.9f, 0.82f, 0.95f);
				((TMP_Text)_emptyText).rectTransform.anchorMin = Vector2.zero;
				((TMP_Text)_emptyText).rectTransform.anchorMax = Vector2.one;
				((TMP_Text)_emptyText).rectTransform.offsetMin = new Vector2(120f, 160f);
				((TMP_Text)_emptyText).rectTransform.offsetMax = new Vector2(-120f, -170f);
			}
		}

		private static void CreatePageBackground(Transform parent, Color color)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = CreateRectObject("Background", parent);
			StretchToParent(val);
			((Graphic)((Component)val).gameObject.AddComponent<Image>()).color = color;
			((Transform)val).SetAsFirstSibling();
		}

		private static RectTransform CreateRectObject(string objectName, Transform parent)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			GameObject val = new GameObject(objectName, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			return val.GetComponent<RectTransform>();
		}

		private static ScrollRect CreateScrollableContent(Transform parent, out RectTransform content)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("ClimbHistoryRows", new Type[3]
			{
				typeof(RectTransform),
				typeof(RectMask2D),
				typeof(ScrollRect)
			});
			val.transform.SetParent(parent, false);
			ScrollRect component = val.GetComponent<ScrollRect>();
			component.scrollSensitivity = 50f;
			component.elasticity = 0f;
			component.vertical = true;
			component.horizontal = false;
			component.movementType = (MovementType)2;
			GameObject val2 = new GameObject("Content", new Type[3]
			{
				typeof(RectTransform),
				typeof(VerticalLayoutGroup),
				typeof(ContentSizeFitter)
			});
			val2.transform.SetParent(val.transform, false);
			content = val2.GetComponent<RectTransform>();
			content.pivot = new Vector2(0.5f, 1f);
			StretchToParent(content);
			VerticalLayoutGroup component2 = val2.GetComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)component2).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandHeight = false;
			ContentSizeFitter component3 = val2.GetComponent<ContentSizeFitter>();
			component3.verticalFit = (FitMode)2;
			component.content = content;
			return component;
		}

		private static Scrollbar CreateRowsScrollbar(Transform parent)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0057: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Expected O, but got Unknown
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("ClimbHistoryScrollbar", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Scrollbar)
			});
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(1f, 0f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(1f, 0.5f);
			component.offsetMin = new Vector2(-72f, 84f);
			component.offsetMax = new Vector2(-56f, -156f);
			Image component2 = val.GetComponent<Image>();
			((Graphic)component2).color = new Color(0.04f, 0.035f, 0.03f, 0.55f);
			GameObject val2 = new GameObject("Sliding Area", new Type[1] { typeof(RectTransform) });
			val2.transform.SetParent(val.transform, false);
			RectTransform component3 = val2.GetComponent<RectTransform>();
			component3.anchorMin = Vector2.zero;
			component3.anchorMax = Vector2.one;
			component3.offsetMin = new Vector2(2f, 2f);
			component3.offsetMax = new Vector2(-2f, -2f);
			GameObject val3 = new GameObject("Handle", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val3.transform.SetParent(val2.transform, false);
			RectTransform component4 = val3.GetComponent<RectTransform>();
			component4.anchorMin = Vector2.zero;
			component4.anchorMax = Vector2.one;
			component4.offsetMin = Vector2.zero;
			component4.offsetMax = Vector2.zero;
			Image component5 = val3.GetComponent<Image>();
			((Graphic)component5).color = new Color(0.78f, 0.63f, 0.35f, 0.95f);
			Scrollbar component6 = val.GetComponent<Scrollbar>();
			component6.direction = (Direction)2;
			((Selectable)component6).targetGraphic = (Graphic)(object)component5;
			component6.handleRect = component4;
			return component6;
		}

		private static void BuildBackButton()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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_0149: Expected O, but got Unknown
			if (!((Object)(object)_historyPage == (Object)null) && !((Object)(object)_pauseMenuHandler == (Object)null) && !((Object)(object)_parentPage == (Object)null))
			{
				PauseMenuHandler pauseMenuHandler = _pauseMenuHandler;
				_backButton = CreateMenuButton("Back", ((Component)_historyPage).transform);
				_backButton.SetText(GetGameLocalizedText("BACK"));
				_backButton.SetColor(new Color(0.5189f, 0.1297f, 0.1718f));
				_backButton.RectTransform.anchorMin = new Vector2(0.5f, 0f);
				_backButton.RectTransform.anchorMax = new Vector2(0.5f, 0f);
				_backButton.RectTransform.pivot = new Vector2(0.5f, 0f);
				_backButton.RectTransform.anchoredPosition = new Vector2(0f, 36f);
				_backButton.RectTransform.sizeDelta = new Vector2(220f, _backButton.RectTransform.sizeDelta.y);
				((UnityEvent)_backButton.Button.onClick).AddListener((UnityAction)delegate
				{
					//IL_000b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0015: Expected O, but got Unknown
					((UIPageHandler)pauseMenuHandler).TransistionToPage(ResolveHistoryBackTarget(), (PageTransistion)new SetActivePageTransistion());
				});
			}
		}

		private static void BuildDetailsPage()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: 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_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: 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_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: 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)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: 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_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0465: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04df: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_050b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0570: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_060f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0633: Unknown result type (might be due to invalid IL or missing references)
			//IL_0649: Unknown result type (might be due to invalid IL or missing references)
			//IL_065f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0675: Unknown result type (might be due to invalid IL or missing references)
			//IL_06da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0725: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Expected O, but got Unknown
			//IL_078f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0758: Unknown result type (might be due to invalid IL or missing references)
			//IL_075d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0763: Expected O, but got Unknown
			//IL_07c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_07cd: Expected O, but got Unknown
			if (!((Object)(object)_historyPage == (Object)null) && !((Object)(object)_pauseMenuHandler == (Object)null))
			{
				GameObject val = new GameObject("ClimbInfoTracker_DetailsPage", new Type[1] { typeof(RectTransform) });
				val.transform.SetParent(((Component)_historyPage).transform.parent, false);
				RectTransform component = val.GetComponent<RectTransform>();
				StretchToParent(component);
				_detailsPage = val.AddComponent<ClimbHistoryDetailsPage>();
				_detailsPage.ParentPage = (UIPage)(object)_historyPage;
				_detailsPage.OnOpened = delegate
				{
					RebuildDetailsLayout();
					ConfigureDetailsPlayerNavigation();
					FocusDetailsCloseButton();
				};
				_detailsPage.OnClosing = OnDetailsPageClosing;
				RectTransform val2 = CreateRectObject("Backdrop", ((Component)_detailsPage).transform);
				StretchToParent(val2);
				Image val3 = ((Component)val2).gameObject.AddComponent<Image>();
				((Graphic)val3).color = new Color(0f, 0f, 0f, 0.62f);
				((Graphic)val3).raycastTarget = true;
				RectTransform val4 = CreateRectObject("DetailsPanel", ((Component)_detailsPage).transform);
				val4.anchorMin = new Vector2(0.14f, 0.14f);
				val4.anchorMax = new Vector2(0.86f, 0.86f);
				val4.offsetMin = Vector2.zero;
				val4.offsetMax = Vector2.zero;
				Image val5 = ((Component)val4).gameObject.AddComponent<Image>();
				((Graphic)val5).color = new Color(0.11f, 0.09f, 0.08f, 0.97f);
				_detailsTitleText = CreateText((Transform)(object)val4, "DetailsTitle", 38f, (TextAlignmentOptions)514);
				((TMP_Text)_detailsTitleText).enableAutoSizing = true;
				((TMP_Text)_detailsTitleText).fontSizeMin = 24f;
				((TMP_Text)_detailsTitleText).fontSizeMax = 38f;
				((TMP_Text)_detailsTitleText).rectTransform.anchorMin = new Vector2(0.18f, 0.89f);
				((TMP_Text)_detailsTitleText).rectTransform.anchorMax = new Vector2(0.82f, 0.98f);
				((TMP_Text)_detailsTitleText).rectTransform.offsetMin = Vector2.zero;
				((TMP_Text)_detailsTitleText).rectTransform.offsetMax = Vector2.zero;
				_detailsCloseButton = CreateMenuButton(ClimbLocalization.Get(ClimbText.Close), (Transform)(object)val4);
				_detailsCloseButton.SetColor(new Color(0.5189f, 0.1297f, 0.1718f));
				_detailsCloseButton.RectTransform.anchorMin = new Vector2(1f, 1f);
				_detailsCloseButton.RectTransform.anchorMax = new Vector2(1f, 1f);
				_detailsCloseButton.RectTransform.pivot = new Vector2(1f, 1f);
				_detailsCloseButton.RectTransform.anchoredPosition = new Vector2(-20f, -16f);
				_detailsCloseButton.RectTransform.sizeDelta = new Vector2(112f, 46f);
				ConfigureRowActionButtonText(_detailsCloseButton);
				ButtonClickedEvent onClick = _detailsCloseButton.Button.onClick;
				object obj = <>O.<4>__CloseDetailsPage;
				if (obj == null)
				{
					UnityAction val6 = CloseDetailsPage;
					<>O.<4>__CloseDetailsPage = val6;
					obj = (object)val6;
				}
				((UnityEvent)onClick).AddListener((UnityAction)obj);
				_detailsMetadataText = CreateText((Transform)(object)val4, "DetailsMetadata", 28f, (TextAlignmentOptions)257);
				((TMP_Text)_detailsMetadataText).richText = true;
				((TMP_Text)_detailsMetadataText).textWrappingMode = (TextWrappingModes)1;
				((TMP_Text)_detailsMetadataText).overflowMode = (TextOverflowModes)0;
				((TMP_Text)_detailsMetadataText).lineSpacing = 4f;
				((TMP_Text)_detailsMetadataText).rectTransform.anchorMin = new Vector2(0f, 0.68f);
				((TMP_Text)_detailsMetadataText).rectTransform.anchorMax = new Vector2(1f, 0.86f);
				((TMP_Text)_detailsMetadataText).rectTransform.offsetMin = new Vector2(36f, 0f);
				((TMP_Text)_detailsMetadataText).rectTransform.offsetMax = new Vector2(-36f, 0f);
				RectTransform val7 = CreateRectObject("DetailsDivider", (Transform)(object)val4);
				val7.anchorMin = new Vector2(0f, 0.66f);
				val7.anchorMax = new Vector2(1f, 0.66f);
				val7.pivot = new Vector2(0.5f, 0.5f);
				val7.offsetMin = new Vector2(36f, -1f);
				val7.offsetMax = new Vector2(-36f, 1f);
				((Graphic)((Component)val7).gameObject.AddComponent<Image>()).color = new Color(0.78f, 0.63f, 0.35f, 0.9f);
				RectTransform val8 = CreateRectObject("MapRouteColumn", (Transform)(object)val4);
				val8.anchorMin = new Vector2(0f, 0.13f);
				val8.anchorMax = new Vector2(0.62f, 0.64f);
				val8.offsetMin = new Vector2(36f, 0f);
				val8.offsetMax = new Vector2(-18f, 0f);
				_detailsRouteTitleText = CreateDetailsColumnTitle((Transform)(object)val8, "MapRouteTitle");
				_detailsRouteScrollRect = CreateDetailsListScroll((Transform)(object)val8, "DetailsRoute", out _detailsRouteContent);
				_detailsRouteEmptyText = CreateText((Transform)(object)val8, "MapRouteEmpty", 24f, (TextAlignmentOptions)514);
				((Graphic)_detailsRouteEmptyText).color = new Color(0.88f, 0.84f, 0.76f, 0.92f);
				ConfigureDetailsColumnBody(((TMP_Text)_detailsRouteEmptyText).rectTransform);
				RectTransform val9 = CreateRectObject("DetailsColumnDivider", (Transform)(object)val4);
				val9.anchorMin = new Vector2(0.62f, 0.13f);
				val9.anchorMax = new Vector2(0.62f, 0.64f);
				val9.offsetMin = new Vector2(-1f, 0f);
				val9.offsetMax = new Vector2(1f, 0f);
				((Graphic)((Component)val9).gameObject.AddComponent<Image>()).color = new Color(0.78f, 0.63f, 0.35f, 0.65f);
				RectTransform val10 = CreateRectObject("OtherPlayersColumn", (Transform)(object)val4);
				val10.anchorMin = new Vector2(0.62f, 0.13f);
				val10.anchorMax = new Vector2(1f, 0.64f);
				val10.offsetMin = new Vector2(18f, 0f);
				val10.offsetMax = new Vector2(-36f, 0f);
				_detailsPlayersTitleText = CreateDetailsColumnTitle((Transform)(object)val10, "OtherPlayersTitle");
				_detailsPlayersScrollRect = CreateDetailsListScroll((Transform)(object)val10, "DetailsPlayers", out _detailsPlayersContent);
				_detailsPlayersEmptyText = CreateText((Transform)(object)val10, "OtherPlayersEmpty", 22f, (TextAlignmentOptions)514);
				((Graphic)_detailsPlayersEmptyText).color = new Color(0.88f, 0.84f, 0.76f, 0.92f);
				((TMP_Text)_detailsPlayersEmptyText).textWrappingMode = (TextWrappingModes)1;
				ConfigureDetailsColumnBody(((TMP_Text)_detailsPlayersEmptyText).rectTransform);
				_detailsLoadButton = CreateMenuButton(ClimbLocalization.Get(ClimbText.LoadMapSettings), (Transform)(object)val4);