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 HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PEAKLib.UI; using PEAKLib.UI.Elements; using Photon.Pun; using Photon.Realtime; using Steamworks; using TMPro; using TerrainRandomiser; using UnityEngine; 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.1.3.0")] [assembly: AssemblyInformationalVersion("0.1.3+a87564d50f3eb9e010b66677ece5c9eb3ccb3264")] [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.1.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [CompilerGenerated] internal sealed class <>z__ReadOnlySingleElementList : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator { object IEnumerator.Current => _item; T IEnumerator.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.Count => 1; T IReadOnlyList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection.Count => 1; bool ICollection.IsReadOnly => true; T IList.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.Default.Equals(_item, (T)value); } int IList.IndexOf(object value) { if (!EqualityComparer.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 IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return EqualityComparer.Default.Equals(_item, item); } void ICollection.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { if (!EqualityComparer.Default.Equals(_item, item)) { return -1; } return 0; } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.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 class ClimbNetworkMode { internal const string Offline = "Offline"; internal const string Multiplayer = "Multiplayer"; } [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 MapBiomes { get; set; } = new List(); } [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; } } [DataContract] internal sealed class ClimbHistoryData { [DataMember(Order = 1)] public int SchemaVersion { get; set; } = 6; [DataMember(Order = 2)] public List Records { get; set; } = new List(); [DataMember(Order = 3, EmitDefaultValue = false)] public ClimbRecord? ActiveRecord { get; set; } } internal sealed class ClimbHistory { private const int CurrentSchemaVersion = 6; private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings { ConstructorHandling = (ConstructorHandling)1, Converters = { (JsonConverter)new StringEnumConverter() } }; private readonly string _filePath; private ClimbHistoryData _data; internal ClimbRecord? ActiveRecord => _data.ActiveRecord; internal ClimbHistory() { _filePath = Path.Combine(Application.persistentDataPath, "ClimbInfoTracker", "ClimbInfoTracker.json"); _data = Load(); Save(); } internal IReadOnlyList GetRecords() { ClimbRecord activeRecord = _data.ActiveRecord; if (activeRecord == null) { return _data.Records.ToArray(); } List records = _data.Records; List list = new List(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); } _data.ActiveRecord = record; Save(); } internal bool TryResumeMultiplayerRoom(ClimbRecord currentRecord) { if (currentRecord.NetworkMode != "Multiplayer" || string.IsNullOrWhiteSpace(currentRecord.PhotonRoomName)) { return false; } ClimbRecord activeRecord = _data.ActiveRecord; if (activeRecord != null && IsRoomResumeCandidate(activeRecord, currentRecord.PhotonRoomName)) { RefreshResumedRecord(activeRecord, currentRecord); Save(); return true; } for (int num = _data.Records.Count - 1; num >= 0; num--) { ClimbRecord climbRecord = _data.Records[num]; if (IsRoomResumeCandidate(climbRecord, currentRecord.PhotonRoomName)) { if (_data.ActiveRecord != null) { FinalizeActive("Abandoned", _data.ActiveRecord.DurationSeconds); } _data.Records.RemoveAt(num); RefreshResumedRecord(climbRecord, currentRecord); _data.ActiveRecord = climbRecord; Save(); return true; } } return false; } internal void Snapshot(float durationSeconds, float currentHeightMeters, string biome, int playerCount, string networkMode, string photonRoomName) { ClimbRecord activeRecord = _data.ActiveRecord; if (activeRecord != null) { activeRecord.DurationSeconds = Math.Max(activeRecord.DurationSeconds, durationSeconds); activeRecord.CurrentHeightMeters = Math.Max(activeRecord.CurrentHeightMeters, currentHeightMeters); UpdateBiome(activeRecord, biome); activeRecord.PlayerCount = Math.Max(1, playerCount); UpdateNetworkState(activeRecord, networkMode, photonRoomName); Save(); } } internal void EnsureActiveMapBiomes(IReadOnlyList mapBiomes) { ClimbRecord activeRecord = _data.ActiveRecord; if (activeRecord != null && (activeRecord.MapBiomes == null || activeRecord.MapBiomes.Count <= 0) && mapBiomes.Count != 0) { activeRecord.MapBiomes = CopyMapBiomes(mapBiomes); Save(); } } 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 UpdateActiveRunId(string runId) { ClimbRecord activeRecord = _data.ActiveRecord; if (activeRecord != null && !string.IsNullOrEmpty(runId) && !(activeRecord.RunId == runId)) { activeRecord.RunId = runId; Save(); } } 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(); } return flag; } internal void Complete(string outcome, float durationSeconds, float currentHeightMeters, string biome, int playerCount, string networkMode, string photonRoomName) { ClimbRecord activeRecord = _data.ActiveRecord; if (activeRecord != null) { activeRecord.CurrentHeightMeters = Math.Max(activeRecord.CurrentHeightMeters, currentHeightMeters); UpdateBiome(activeRecord, biome); activeRecord.PlayerCount = Math.Max(1, playerCount); UpdateNetworkState(activeRecord, networkMode, photonRoomName); FinalizeActive(outcome, durationSeconds); } } private static void UpdateBiome(ClimbRecord record, string biome) { if (!string.IsNullOrWhiteSpace(biome)) { record.Biome = biome; } } private static bool IsRoomResumeCandidate(ClimbRecord? record, string photonRoomName) { if (record != null && record.NetworkMode == "Multiplayer" && string.Equals(record.PhotonRoomName, photonRoomName, StringComparison.Ordinal)) { if (!(record.Outcome == "InProgress")) { return record.Outcome == "Abandoned"; } return true; } return false; } private static void RefreshResumedRecord(ClimbRecord record, ClimbRecord currentRecord) { string runId = record.RunId; string startedAtUtc = record.StartedAtUtc; record.RunId = runId; record.StartedAtUtc = startedAtUtc; record.EndedAtUtc = ""; record.Outcome = "InProgress"; record.DurationSeconds = currentRecord.DurationSeconds; record.CurrentHeightMeters = currentRecord.CurrentHeightMeters; record.Ascent = currentRecord.Ascent; record.PlayerCount = currentRecord.PlayerCount; record.IsCustomRun = currentRecord.IsCustomRun; record.IsMiniRun = currentRecord.IsMiniRun; record.Level = currentRecord.Level; record.Biome = currentRecord.Biome; record.MapBiomes = CopyMapBiomes(currentRecord.MapBiomes); record.TerrainRandomiserEnabled = false; record.TerrainRandomiserSeed = -1; record.TerrainRandomiserMapSettingsBrotliBase64 = ""; record.NetworkMode = currentRecord.NetworkMode; record.PhotonRoomName = currentRecord.PhotonRoomName; } 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) { DateTimeOffset utcNow = DateTimeOffset.UtcNow; activeRecord.Outcome = outcome; activeRecord.DurationSeconds = Math.Max(0f, durationSeconds); activeRecord.EndedAtUtc = utcNow.ToString("O", CultureInfo.InvariantCulture); _data.Records.RemoveAll((ClimbRecord record) => record.RunId == activeRecord.RunId); _data.Records.Add(activeRecord); _data.ActiveRecord = null; Save(); } } private ClimbHistoryData Load() { if (!File.Exists(_filePath)) { return new ClimbHistoryData(); } try { string text = File.ReadAllText(_filePath); ClimbHistoryData climbHistoryData = JsonConvert.DeserializeObject(text, JsonSettings); if (climbHistoryData == null) { return new ClimbHistoryData(); } climbHistoryData.SchemaVersion = 6; ClimbHistoryData climbHistoryData2 = climbHistoryData; if (climbHistoryData2.Records == null) { List list = (climbHistoryData2.Records = new List()); } NormalizeRecords(climbHistoryData.Records); if (climbHistoryData.ActiveRecord != null) { NormalizeRecord(climbHistoryData.ActiveRecord); } return climbHistoryData; } catch (Exception arg) { Plugin.Logger.LogError((object)$"Failed to load climb history: {arg}"); return new ClimbHistoryData(); } } private void Save() { string text = _filePath + ".tmp"; try { string directoryName = Path.GetDirectoryName(_filePath); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } string contents = JsonConvert.SerializeObject((object)_data, (Formatting)0, JsonSettings); File.WriteAllText(text, contents); File.Copy(text, _filePath, overwrite: true); File.Delete(text); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Failed to save climb history: {arg}"); try { if (File.Exists(text)) { File.Delete(text); } } catch (Exception ex) { Plugin.Logger.LogDebug((object)("Failed to remove temporary climb history file: " + ex.Message)); } } } private static List CopyMapBiomes(IReadOnlyList mapBiomes) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) List list = new List(mapBiomes.Count); foreach (MapBiomeInfo mapBiome in mapBiomes) { list.Add(new MapBiomeInfo { BiomeType = mapBiome.BiomeType, Variant = mapBiome.Variant, OpenTomb = mapBiome.OpenTomb }); } return list; } private static void NormalizeRecords(List records) { foreach (ClimbRecord record in records) { NormalizeRecord(record); } } private static void NormalizeRecord(ClimbRecord record) { if (record.MapBiomes == null) { List list = (record.MapBiomes = new List()); } } } internal static class ClimbHistoryUi { [CompilerGenerated] private static class <>O { public static BuilderDelegate <0>__BuildPauseMenu; public static Action <1>__OnLanguageChanged; public static Func <2>__EscapeRichText; public static Func <3>__LocalizeBiomeTextId; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__28_0; public static Func <>9__35_0; public static Func <>9__36_0; public static Func <>9__61_0; internal void b__28_0() { Plugin.Logger.LogDebug((object)("Climb history page OnOpen fired. " + DescribePageState() + ", " + $"frame={Time.frameCount}.")); RefreshPage(); } internal bool b__35_0(ClimbRecord record) { return record.Outcome == "Summited"; } internal DateTimeOffset b__36_0(ClimbRecord record) { return ParseDate(record.StartedAtUtc); } internal bool b__61_0(string field) { return !string.IsNullOrWhiteSpace(field); } } private static readonly List Rows = new List(); private static bool _registered; private static bool _languageSubscribed; private static Transform? _pauseMenuParent; private static PauseMenuHandler? _pauseMenuHandler; private static PauseMenuMainPage? _parentPage; private static PeakChildPage? _historyPage; private static PeakMenuButton? _openButton; private static PeakMenuButton? _backButton; private static RectTransform? _rowsContent; private static TextMeshProUGUI? _titleText; private static TextMeshProUGUI? _summaryText; private static TextMeshProUGUI? _hintText; private static TextMeshProUGUI? _emptyText; private static TMP_FontAsset? _vanillaFont; private const float RowHeight = 132f; private const float RowActionRightPadding = 24f; private const float RowActionSpacing = 8f; private const float RowActionHeight = 44f; private const float RowMapActionWidth = 86f; private const float RowDeleteActionWidth = 92f; private const float RowActionFontSize = 20f; private static readonly IReadOnlyDictionary BiomeTextIds = new Dictionary { [(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" } }; private static readonly HashSet HasVariants = new HashSet { (BiomeType)0, (BiomeType)1, (BiomeType)2, (BiomeType)6, (BiomeType)7 }; private static readonly IReadOnlyDictionary> SimplifiedChineseVariantNames = new Dictionary> { [(BiomeType)0] = new Dictionary { ["Default"] = "默认", ["SnakeBeach"] = "蛇岩", ["RedBeach"] = "赤沙", ["BlueBeach"] = "蓝沙", ["JellyHell"] = "水母地狱", ["BlackSand"] = "黑沙" }, [(BiomeType)1] = new Dictionary { ["Default"] = "默认", ["Lava"] = "熔岩管", ["Pillars"] = "巨柱", ["Thorny"] = "巨棘藤", ["Bombs"] = "爆菇", ["Ivy"] = "紫毒藤", ["SkyJungle"] = "浮岛" }, [(BiomeType)7] = new Dictionary { ["Default"] = "默认", ["CaveMania"] = "洞窟丛生", ["DeepWater"] = "赤水孢泽", ["BombBeetle"] = "爆菇甲虫", ["DeepWoods"] = "幽深密林", ["Clearcut"] = "皆伐菌原" }, [(BiomeType)2] = new Dictionary { ["Default"] = "默认", ["Lava"] = "熔岩管", ["Spiky"] = "冰刺", ["GeyserHell"] = "间歇泉地狱" }, [(BiomeType)6] = new Dictionary { ["Default"] = "默认", ["ScorpionsHell"] = "毒蝎地狱", ["CactusHell"] = "峭壁仙人掌地狱", ["CactusForest"] = "高原仙人掌林", ["DynamiteHell"] = "炸药地狱", ["TornadoHell"] = "龙卷风地狱", ["TumblerHell"] = "风滚草地狱" } }; internal static void Register() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown Plugin.Logger.LogDebug((object)($"Registering climb history UI. registered={_registered}, " + $"languageSubscribed={_languageSubscribed}, frame={Time.frameCount}.")); if (!_registered) { _registered = true; object obj = <>O.<0>__BuildPauseMenu; if (obj == null) { BuilderDelegate val = BuildPauseMenu; <>O.<0>__BuildPauseMenu = val; obj = (object)val; } MenuAPI.AddToPauseMenu((BuilderDelegate)obj); 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() { if (_languageSubscribed) { LocalizedText.OnLangugageChanged = (Action)Delegate.Remove(LocalizedText.OnLangugageChanged, new Action(OnLanguageChanged)); _languageSubscribed = false; } } private static void BuildPauseMenu(Transform parent) { if ((Object)(object)_pauseMenuParent == (Object)null || (Object)(object)_pauseMenuParent != (Object)(object)parent) { ResetBuiltUi(); } _pauseMenuParent = parent; Plugin.Logger.LogDebug((object)("Building climb history pause menu. parent=" + DescribeTransform(parent) + ", " + $"existingPage={DescribeObject((Object?)(object)_historyPage)}, frame={Time.frameCount}.")); _pauseMenuHandler = ((Component)parent).GetComponentInParent(); _parentPage = ((Component)parent).GetComponent(); 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(parent); Plugin.Logger.LogDebug((object)("Finished building climb history pause menu entry. openButton=" + DescribeObject((Object?)(object)_openButton) + ", deferredPage=" + DescribeObject((Object?)(object)_historyPage) + ".")); } private static bool EnsureHistoryPage() { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown 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}.")); _historyPage = MenuAPI.CreateChildPage("ClimbInfoTracker_HistoryPage", (UIPage)(object)_parentPage); Plugin.Logger.LogDebug((object)("Created climb history child page. " + DescribePageState() + ", " + $"frame={Time.frameCount}.")); PeakChildPage obj = _historyPage.CreateBackground((Color?)new Color(0f, 0f, 0f, 0.87f)); object obj2 = <>c.<>9__28_0; if (obj2 == null) { UnityAction val = delegate { Plugin.Logger.LogDebug((object)("Climb history page OnOpen fired. " + DescribePageState() + ", " + $"frame={Time.frameCount}.")); RefreshPage(); }; <>c.<>9__28_0 = val; obj2 = (object)val; } obj.SetOnOpen((UnityAction)obj2); BuildHeader(); BuildContent(); BuildBackButton(); Plugin.Logger.LogDebug((object)("Built climb history controls. title=" + DescribeObject((Object?)(object)_titleText) + ", rowsContent=" + DescribeRect(_rowsContent) + ", backButton=" + DescribeObject((Object?)(object)_backButton) + ".")); ((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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_historyPage == (Object)null)) { PeakElement val = ElementExtensions.SetSize(ElementExtensions.SetPivot(ElementExtensions.SetPosition(ElementExtensions.SetAnchorMinMax(ElementExtensions.ParentTo(new GameObject("Header"), (Component)(object)_historyPage).AddComponent(), new Vector2(0.5f, 1f)), new Vector2(0f, -32f)), new Vector2(0.5f, 1f)), new Vector2(900f, 120f)); _titleText = CreateText(((Component)val).transform, "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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_historyPage == (Object)null)) { PeakElement val = ElementExtensions.SetSize(ElementExtensions.SetPosition(ElementExtensions.SetAnchorMinMax(ElementExtensions.SetPivot(ElementExtensions.ParentTo(new GameObject("Content").AddComponent(), (Component)(object)_historyPage), new Vector2(0.5f, 1f)), new Vector2(0.5f, 1f)), new Vector2(0f, -140f)), new Vector2(1420f, 840f)); PeakElement val2 = ElementExtensions.ExpandToParent(ElementExtensions.ParentTo(new GameObject("HistoryPanel").AddComponent(), (Component)(object)val)); ((Graphic)((Component)val2).gameObject.AddComponent()).color = new Color(0.11f, 0.09f, 0.08f, 0.76f); _summaryText = CreateText(((Component)val2).transform, "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); _hintText = CreateText(((Component)val2).transform, "Hint", 22f, (TextAlignmentOptions)514); ((Graphic)_hintText).color = new Color(0.88f, 0.84f, 0.76f, 0.92f); ConfigureTopText(((TMP_Text)_hintText).rectTransform, 90f, -78f, -90f, -114f); PeakElement val3 = ElementExtensions.SetSize(ElementExtensions.SetPosition(ElementExtensions.SetPivot(ElementExtensions.SetAnchorMax(ElementExtensions.SetAnchorMin(ElementExtensions.ParentTo(new GameObject("Divider").AddComponent(), (Component)(object)val2), new Vector2(0f, 1f)), new Vector2(1f, 1f)), new Vector2(0.5f, 1f)), new Vector2(0f, -132f)), new Vector2(-120f, 2f)); ((Graphic)((Component)val3).gameObject.AddComponent()).color = new Color(0.78f, 0.63f, 0.35f, 0.9f); PeakScrollableContent val4 = ElementExtensions.SetOffsetMax(ElementExtensions.SetOffsetMin(ElementExtensions.SetAnchorMax(ElementExtensions.SetAnchorMin(ElementExtensions.ParentTo(MenuAPI.CreateScrollableContent("ClimbHistoryRows"), (Component)(object)val2), Vector2.zero), Vector2.one), new Vector2(56f, 84f)), new Vector2(-80f, -156f)); _rowsContent = val4.Content; ScrollRect component = ((Component)val4).GetComponent(); component.verticalScrollbar = CreateRowsScrollbar(((Component)val2).transform); component.verticalScrollbarVisibility = (ScrollbarVisibility)0; _emptyText = CreateText(((Component)val2).transform, "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 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(); 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(); ((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(); 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(); component4.anchorMin = Vector2.zero; component4.anchorMax = Vector2.one; component4.offsetMin = Vector2.zero; component4.offsetMax = Vector2.zero; Image component5 = val3.GetComponent(); ((Graphic)component5).color = new Color(0.78f, 0.63f, 0.35f, 0.95f); Scrollbar component6 = val.GetComponent(); component6.direction = (Direction)2; ((Selectable)component6).targetGraphic = (Graphic)(object)component5; component6.handleRect = component4; return component6; } private static void BuildBackButton() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown if (!((Object)(object)_historyPage == (Object)null) && !((Object)(object)_pauseMenuHandler == (Object)null) && !((Object)(object)_parentPage == (Object)null)) { PauseMenuHandler pauseMenuHandler = _pauseMenuHandler; PauseMenuMainPage parentPage = _parentPage; _backButton = ElementExtensions.SetPosition(ElementExtensions.SetPivot(ElementExtensions.SetAnchorMinMax(ElementExtensions.ParentTo(ElementExtensions.SetLocalizationIndex(MenuAPI.CreateMenuButton("Back"), "BACK").SetColor(new Color(0.5189f, 0.1297f, 0.1718f), true), (Component)(object)_historyPage), new Vector2(0.5f, 0f)), new Vector2(0.5f, 0f)), new Vector2(0f, 36f)).SetWidth(220f).OnClick((UnityAction)delegate { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown ((UIPageHandler)pauseMenuHandler).TransistionToPage((UIPage)(object)parentPage, (PageTransistion)new SetActivePageTransistion()); }); _historyPage.SetBackButton(_backButton.Button); } } private static void BuildOpenButton(Transform parent) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_openButton != (Object)null) { Plugin.Logger.LogDebug((object)"Skipped climb history open button build because it already exists."); } else { if ((Object)(object)_pauseMenuHandler == (Object)null) { return; } PauseMenuHandler pauseMenuHandler = _pauseMenuHandler; _openButton = ElementExtensions.ParentTo(MenuAPI.CreatePauseMenuButton(ClimbLocalization.Get(ClimbText.Button)), parent).OnClick((UnityAction)delegate { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown Plugin.Logger.LogDebug((object)("Climb history button clicked. Before transition: " + DescribePageState() + ", " + $"rows={Rows.Count}, frame={Time.frameCount}.")); if (EnsureHistoryPage() && !((Object)(object)_historyPage == (Object)null)) { ((UIPageHandler)pauseMenuHandler).TransistionToPage((UIPage)(object)_historyPage, (PageTransistion)new SetActivePageTransistion()); } }); RectTransform rectTransform = ((PeakElement)_openButton).RectTransform; rectTransform.anchorMin = new Vector2(0.5f, 0f); rectTransform.anchorMax = new Vector2(0.5f, 0f); rectTransform.pivot = new Vector2(0.5f, 0f); rectTransform.sizeDelta = new Vector2(277f, rectTransform.sizeDelta.y); rectTransform.anchoredPosition = new Vector2(0f, 36f); } } private static void ResetBuiltUi() { foreach (GameObject row in Rows) { if ((Object)(object)row != (Object)null) { Object.Destroy((Object)(object)row); } } Rows.Clear(); _historyPage = null; _openButton = null; _backButton = null; _rowsContent = null; _titleText = null; _summaryText = null; _hintText = null; _emptyText = null; } private static void RefreshPage() { Plugin.Logger.LogDebug((object)("Refreshing climb history page. " + DescribePageState() + ", " + $"rowsContent={DescribeRect(_rowsContent)}, existingRows={Rows.Count}, " + $"frame={Time.frameCount}.")); EnsureFonts(); Plugin.Tracker.SnapshotActiveRun(); IReadOnlyList records = Plugin.History.GetRecords(); int num = records.Count((ClimbRecord record) => record.Outcome == "Summited"); Plugin.Logger.LogDebug((object)($"Loaded climb history records for UI. records={records.Count}, " + $"summits={num}, language={ClimbLocalization.CurrentCulture.Name}.")); SetLocalizedText((TMP_Text?)(object)_titleText, ClimbLocalization.Get(ClimbText.Title)); SetLocalizedText((TMP_Text?)(object)_summaryText, ClimbLocalization.Format(ClimbText.Summary, records.Count, num)); SetLocalizedText((TMP_Text?)(object)_hintText, ClimbLocalization.Get(ClimbText.Hint)); SetLocalizedText((TMP_Text?)(object)_emptyText, ClimbLocalization.Get(ClimbText.Empty)); if ((Object)(object)_openButton != (Object)null) { _openButton.SetText(ClimbLocalization.Get(ClimbText.Button)); ApplyFont(((PeakLocalizableElement)_openButton).Text); } if ((Object)(object)_backButton != (Object)null) { ApplyFont(((PeakLocalizableElement)_backButton).Text); } RefreshRows(records); RebuildLayout(); Plugin.Logger.LogDebug((object)("Finished refreshing climb history page. " + DescribePageState() + ", " + $"rowsContent={DescribeRect(_rowsContent)}, renderedRows={Rows.Count}, " + $"emptyVisible={(Object)(object)_emptyText != (Object)null && ((Component)_emptyText).gameObject.activeInHierarchy}, " + $"frame={Time.frameCount}.")); } private static void RefreshRows(IReadOnlyList records) { if ((Object)(object)_rowsContent == (Object)null) { Plugin.Logger.LogWarning((object)("Cannot refresh climb history rows because rows content is missing. " + $"records={records.Count}, frame={Time.frameCount}.")); return; } foreach (GameObject row in Rows) { row.transform.SetParent((Transform)null, false); Object.Destroy((Object)(object)row); } Rows.Clear(); List list = records.OrderByDescending((ClimbRecord record) => ParseDate(record.StartedAtUtc)).ToList(); if ((Object)(object)_emptyText != (Object)null) { ((Component)_emptyText).gameObject.SetActive(list.Count == 0); } for (int num = 0; num < list.Count; num++) { GameObject val = CreateRow(list[num], num); val.transform.SetParent((Transform)(object)_rowsContent, false); Rows.Add(val); } } private static GameObject CreateRow(ClimbRecord record, int index) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ClimbRecordRow", new Type[3] { typeof(RectTransform), typeof(Image), typeof(LayoutElement) }); ((Graphic)val.GetComponent()).color = ((index % 2 == 0) ? new Color(0.2f, 0.15f, 0.11f, 0.72f) : new Color(0.16f, 0.12f, 0.09f, 0.72f)); LayoutElement component = val.GetComponent(); component.preferredHeight = 132f; component.minHeight = 132f; RectTransform component2 = val.GetComponent(); component2.sizeDelta = new Vector2(component2.sizeDelta.x, 132f); bool flag = CanSaveMapSettings(record); bool flag2 = CanLoadMapSettings(record); TextMeshProUGUI val2 = CreateText(val.transform, "RecordText", 28f, (TextAlignmentOptions)257); ((TMP_Text)val2).richText = true; ((TMP_Text)val2).lineSpacing = 6f; ((TMP_Text)val2).overflowMode = (TextOverflowModes)0; ((TMP_Text)val2).rectTransform.anchorMin = Vector2.zero; ((TMP_Text)val2).rectTransform.anchorMax = Vector2.one; ((TMP_Text)val2).rectTransform.offsetMin = new Vector2(24f, 8f); ((TMP_Text)val2).rectTransform.offsetMax = new Vector2(0f - CalculateRowActionReservedWidth(flag2, flag), -8f); ((TMP_Text)val2).text = BuildRowText(record); PeakMenuButton val3 = CreateDeleteButton(val.transform, record.RunId, 24f); ApplyFont((TMP_Text)(object)val2); ApplyFont(((PeakLocalizableElement)val3).Text); if (flag2) { PeakMenuButton val4 = CreateLoadMapSettingsButton(val.transform, record, 124f + (flag ? 94f : 0f)); ApplyFont(((PeakLocalizableElement)val4).Text); } if (flag) { PeakMenuButton val5 = CreateSaveMapSettingsButton(val.transform, record, 124f); ApplyFont(((PeakLocalizableElement)val5).Text); } return val; } private static float CalculateRowActionReservedWidth(bool canLoadMapSettings, bool canSaveMapSettings) { float num = 140f; if (canSaveMapSettings) { num += 94f; } if (canLoadMapSettings) { num += 94f; } return num; } private static bool CanSaveMapSettings(ClimbRecord record) { if (TerrainRandomiserCompatibility.Loaded) { return !string.IsNullOrWhiteSpace(record.TerrainRandomiserMapSettingsBrotliBase64); } return false; } private static bool CanLoadMapSettings(ClimbRecord record) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (CanSaveMapSettings(record)) { Scene activeScene = SceneManager.GetActiveScene(); return ((Scene)(ref activeScene)).name == "Airport"; } return false; } private static PeakMenuButton CreateLoadMapSettingsButton(Transform parent, ClimbRecord record, float rightOffset) { //IL_0028: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) PeakMenuButton val = ElementExtensions.SetPosition(ElementExtensions.SetPivot(ElementExtensions.SetAnchorMinMax(ElementExtensions.ParentTo(MenuAPI.CreateMenuButton(ClimbLocalization.Get(ClimbText.LoadMapSettings)).SetColor(new Color(0.23f, 0.28f, 0.42f), true), parent), new Vector2(1f, 0.5f)), new Vector2(1f, 0.5f)), new Vector2(0f - rightOffset, 0f)).SetWidth(86f).OnClick((UnityAction)delegate { if (TerrainRandomiserCompatibility.LoadMapSettings(record.TerrainRandomiserMapSettingsBrotliBase64)) { Plugin.Logger.LogInfo((object)"Loaded TerrainRandomiser map settings."); } }); ((PeakElement)val).RectTransform.sizeDelta = new Vector2(86f, 44f); val.SetText(ClimbLocalization.Get(ClimbText.LoadMapSettings)); ConfigureRowActionButtonText(val); return val; } private static PeakMenuButton CreateSaveMapSettingsButton(Transform parent, ClimbRecord record, float rightOffset) { //IL_0028: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) PeakMenuButton val = ElementExtensions.SetPosition(ElementExtensions.SetPivot(ElementExtensions.SetAnchorMinMax(ElementExtensions.ParentTo(MenuAPI.CreateMenuButton(ClimbLocalization.Get(ClimbText.SaveMapSettings)).SetColor(new Color(0.23f, 0.36f, 0.18f), true), parent), new Vector2(1f, 0.5f)), new Vector2(1f, 0.5f)), new Vector2(0f - rightOffset, 0f)).SetWidth(86f).OnClick((UnityAction)delegate { string text = TerrainRandomiserCompatibility.SaveMapSettings(record.TerrainRandomiserMapSettingsBrotliBase64, record.StartedAtUtc); if (text != null) { Plugin.Logger.LogInfo((object)("Saved TerrainRandomiser map settings to " + text + ".")); } }); ((PeakElement)val).RectTransform.sizeDelta = new Vector2(86f, 44f); val.SetText(ClimbLocalization.Get(ClimbText.SaveMapSettings)); ConfigureRowActionButtonText(val); return val; } private static PeakMenuButton CreateDeleteButton(Transform parent, string runId, float rightOffset) { //IL_0028: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) PeakMenuButton val = ElementExtensions.SetPosition(ElementExtensions.SetPivot(ElementExtensions.SetAnchorMinMax(ElementExtensions.ParentTo(MenuAPI.CreateMenuButton(ClimbLocalization.Get(ClimbText.Delete)).SetColor(new Color(0.5189f, 0.1297f, 0.1718f), true), parent), new Vector2(1f, 0.5f)), new Vector2(1f, 0.5f)), new Vector2(0f - rightOffset, 0f)).SetWidth(92f).OnClick((UnityAction)delegate { Plugin.Tracker.DeleteRecord(runId); RefreshPage(); }); ((PeakElement)val).RectTransform.sizeDelta = new Vector2(92f, 44f); val.SetText(ClimbLocalization.Get(ClimbText.Delete)); ConfigureRowActionButtonText(val); return val; } private static void ConfigureRowActionButtonText(PeakMenuButton button) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) TMP_Text text = ((PeakLocalizableElement)button).Text; text.enableAutoSizing = false; text.fontSize = 20f; text.alignment = (TextAlignmentOptions)514; text.textWrappingMode = (TextWrappingModes)0; text.overflowMode = (TextOverflowModes)1; text.rectTransform.anchorMin = Vector2.zero; text.rectTransform.anchorMax = Vector2.one; text.rectTransform.offsetMin = new Vector2(4f, 0f); text.rectTransform.offsetMax = new Vector2(-4f, 0f); ((Transform)text.rectTransform).localScale = Vector3.one; } private static string BuildRowText(ClimbRecord record) { string value = FormatDate(record.StartedAtUtc) + " | " + ClimbLocalization.GetOutcome(record.Outcome); string value2 = BuildStatsLine(record); string text = BuildContextLine(record); string text2 = BuildMapBiomesLine(record); if (string.IsNullOrWhiteSpace(text2)) { return string.Format(CultureInfo.InvariantCulture, "{0}\n{1}\n{2}", EscapeRichText(value), EscapeRichText(value2), text); } return string.Format(CultureInfo.InvariantCulture, "{0}\n{1}\n{2}\n{3}", EscapeRichText(value), EscapeRichText(value2), text, text2); } private static string EscapeRichText(string value) { return value.Replace("&", "&", StringComparison.Ordinal).Replace("<", "<", StringComparison.Ordinal).Replace(">", ">", StringComparison.Ordinal); } private static string BuildStatsLine(ClimbRecord record) { string text = TimeSpan.FromSeconds(Math.Max(0f, record.DurationSeconds)).ToString("hh\\:mm\\:ss", CultureInfo.InvariantCulture); string text2 = ClimbLocalization.Format(ClimbText.Players, record.PlayerCount); return JoinFields(text, $"{Mathf.RoundToInt(record.CurrentHeightMeters)} m", text2, EscapeRichText(BuildNetworkModeText(record))); } private static string BuildContextLine(ClimbRecord record) { List list = new List(3) { EscapeRichText(record.Level), EscapeRichText(FormatBiomeName(record.Biome)), EscapeRichText(BuildModeText(record)) }; if (record.TerrainRandomiserEnabled && record.TerrainRandomiserSeed >= 0) { list.Add(BuildTerrainSeedText(record.TerrainRandomiserSeed)); } return JoinFields(list); } private static string BuildMapBiomesLine(ClimbRecord record) { if (record.MapBiomes == null || record.MapBiomes.Count == 0) { return ""; } List list = new List(); foreach (MapBiomeInfo mapBiome in record.MapBiomes) { list.AddRange(BuildMapBiomeFields(mapBiome)); } return JoinFields(list.Select(EscapeRichText)); } private static IEnumerable BuildMapBiomeFields(MapBiomeInfo mapBiome) { if ((int)mapBiome.BiomeType == 3 || (int)mapBiome.BiomeType == 8) { foreach (string biomeDisplayName in GetBiomeDisplayNames(mapBiome.BiomeType)) { yield return biomeDisplayName; } yield break; } string text = GetBiomeDisplayNames(mapBiome.BiomeType).FirstOrDefault() ?? ""; if (!string.IsNullOrWhiteSpace(text)) { List list = new List(); if (HasVariants.Contains(mapBiome.BiomeType) && !string.IsNullOrWhiteSpace(mapBiome.Variant)) { list.Add(FormatVariantName(mapBiome.BiomeType, mapBiome.Variant)); } if ((int)mapBiome.BiomeType == 6) { list.Add(ClimbLocalization.Get(mapBiome.OpenTomb ? ClimbText.TombOpen : ClimbText.TombClosed)); } yield return (list.Count > 0) ? (text + " (" + string.Join(", ", list) + ")") : text; } } private static string FormatVariantName(BiomeType biomeType, string variant) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) if ((int)LocalizedText.CURRENT_LANGUAGE == 9 && SimplifiedChineseVariantNames.TryGetValue(biomeType, out IReadOnlyDictionary value) && value.TryGetValue(variant, out var value2)) { return value2; } return variant; } private unsafe static IEnumerable GetBiomeDisplayNames(BiomeType biomeType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (BiomeTextIds.TryGetValue(biomeType, out string[] value)) { return value.Select(LocalizeBiomeTextId); } return new <>z__ReadOnlySingleElementList(((object)(*(BiomeType*)(&biomeType))/*cast due to .constrained prefix*/).ToString()); } private static string LocalizeBiomeTextId(string textId) { try { string text = LocalizedText.GetText(textId, true); if (!string.IsNullOrWhiteSpace(text) && text != textId) { return text; } } catch (Exception ex) { Plugin.Logger.LogDebug((object)("Failed to localize biome text id '" + textId + "': " + ex.Message)); } return FormatBiomeTextFallback(textId); } private static string FormatBiomeTextFallback(string textId) { string[] array = textId.Split(' '); for (int i = 0; i < array.Length; i++) { string text = array[i]; if (text.Length != 0) { array[i] = text.Substring(0, 1).ToUpperInvariant() + text.Substring(1).ToLowerInvariant(); } } return string.Join(" ", array); } private static string BuildTerrainSeedText(int seed) { return EscapeRichText(ClimbLocalization.Get(ClimbText.TerrainSeed)) + " <" + seed.ToString(CultureInfo.InvariantCulture) + ">"; } private static string FormatBiomeName(string biomeTitle) { if (string.IsNullOrWhiteSpace(biomeTitle)) { return ""; } try { string text = LocalizedText.GetText(biomeTitle, true); return string.IsNullOrWhiteSpace(text) ? biomeTitle : text; } catch (Exception ex) { Plugin.Logger.LogDebug((object)("Failed to localize biome title '" + biomeTitle + "': " + ex.Message)); return biomeTitle; } } private static string BuildModeText(ClimbRecord record) { if (record.IsCustomRun || record.IsMiniRun) { string text = ClimbLocalization.Get(ClimbText.CustomRun); if (!record.IsMiniRun) { return text; } return text + " (" + ClimbLocalization.Get(ClimbText.MiniRun) + ")"; } string text2 = record.Ascent switch { -1 => ClimbLocalization.Get(ClimbText.Tenderfoot), 0 => ClimbLocalization.Get(ClimbText.Peak), _ => ClimbLocalization.Format(ClimbText.Ascent, record.Ascent), }; return ClimbLocalization.Get(ClimbText.NormalRun) + " (" + text2 + ")"; } private static string BuildNetworkModeText(ClimbRecord record) { string networkMode = record.NetworkMode; if (!(networkMode == "Offline")) { if (networkMode == "Multiplayer") { return FormatMultiplayerText(record.PhotonRoomName); } return ""; } return ClimbLocalization.Get(ClimbText.OfflineMode); } private static string FormatMultiplayerText(string photonRoomName) { string text = ClimbLocalization.Get(ClimbText.MultiplayerMode); if (!string.IsNullOrWhiteSpace(photonRoomName)) { return text + " (" + photonRoomName + ")"; } return text; } private static string JoinFields(params string[] fields) { return JoinFields((IEnumerable)fields); } private static string JoinFields(IEnumerable fields) { return string.Join(" | ", fields.Where((string field) => !string.IsNullOrWhiteSpace(field))); } private static DateTimeOffset ParseDate(string value) { if (!DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var result)) { return DateTimeOffset.MinValue; } return result; } private static string FormatDate(string value) { DateTimeOffset dateTimeOffset = ParseDate(value); if (!(dateTimeOffset == DateTimeOffset.MinValue)) { return dateTimeOffset.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); } return value; } private static void SetLocalizedText(TMP_Text? text, string value) { if (!((Object)(object)text == (Object)null)) { text.text = value; ApplyFont(text); } } private static TextMeshProUGUI CreateText(Transform parent, string objectName, float fontSize, TextAlignmentOptions alignment) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(objectName, new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI) }); val.transform.SetParent(parent, false); TextMeshProUGUI component = val.GetComponent(); ((TMP_Text)component).font = _vanillaFont; ((TMP_Text)component).fontSize = fontSize; ((TMP_Text)component).alignment = alignment; ((Graphic)component).color = Color.white; ((TMP_Text)component).overflowMode = (TextOverflowModes)1; ((TMP_Text)component).textWrappingMode = (TextWrappingModes)0; return component; } private static void EnsureFonts() { if (!((Object)(object)_vanillaFont != (Object)null)) { GUIManager instance = GUIManager.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.heroDayText == (Object)null)) { _vanillaFont = ((TMP_Text)instance.heroDayText).font; } } } private static void ApplyFont(TMP_Text text) { EnsureFonts(); if ((Object)(object)_vanillaFont != (Object)null) { text.font = _vanillaFont; } } private static void StretchToParent(RectTransform rectTransform) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = Vector2.zero; rectTransform.offsetMax = Vector2.zero; } private static void ConfigureTopText(RectTransform rectTransform, float left, float top, float right, float bottom) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) rectTransform.anchorMin = new Vector2(0f, 1f); rectTransform.anchorMax = new Vector2(1f, 1f); rectTransform.pivot = new Vector2(0.5f, 1f); rectTransform.offsetMin = new Vector2(left, bottom); rectTransform.offsetMax = new Vector2(right, top); } private static void OnLanguageChanged() { Plugin.Logger.LogDebug((object)("Climb history language changed. language=" + ClimbLocalization.CurrentCulture.Name + ", " + $"frame={Time.frameCount}.")); RefreshPage(); } private static void RebuildLayout() { Canvas.ForceUpdateCanvases(); if ((Object)(object)_rowsContent != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate(_rowsContent); } if ((Object)(object)_historyPage != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate(((Component)_historyPage).GetComponent()); } Canvas.ForceUpdateCanvases(); } private static string DescribePageState() { if ((Object)(object)_historyPage == (Object)null) { return "page=null"; } GameObject gameObject = ((Component)_historyPage).gameObject; RectTransform component = gameObject.GetComponent(); return $"page={((Object)gameObject).name}, activeSelf={gameObject.activeSelf}, " + $"activeInHierarchy={gameObject.activeInHierarchy}, rect={DescribeRect(component)}"; } private static string DescribeTransform(Transform? transform) { if (!((Object)(object)transform == (Object)null)) { return $"{((Object)transform).name}, activeSelf={((Component)transform).gameObject.activeSelf}, " + $"activeInHierarchy={((Component)transform).gameObject.activeInHierarchy}"; } return "null"; } private static string DescribeObject(Object? value) { if (!(value == (Object)null)) { return value.name + " (" + ((object)value).GetType().Name + ")"; } return "null"; } private static string DescribeRect(RectTransform? rectTransform) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rectTransform == (Object)null) { return "null"; } Rect rect = rectTransform.rect; return $"{((Object)rectTransform).name}[size={((Rect)(ref rect)).width:0.##}x{((Rect)(ref rect)).height:0.##}, " + $"position={rectTransform.anchoredPosition}, children={((Transform)rectTransform).childCount}]"; } } internal enum ClimbText { Button, Title, Summary, Hint, Empty, InProgress, Summited, Failed, Abandoned, Players, Tenderfoot, Peak, Ascent, NormalRun, CustomRun, MiniRun, Delete, SaveMapSettings, LoadMapSettings, TerrainSeed, OfflineMode, MultiplayerMode, TombOpen, TombClosed } internal static class ClimbLocalization { private static readonly IReadOnlyDictionary English = new Dictionary { [ClimbText.Button] = "CLIMB RECORDS", [ClimbText.Title] = "Climb Records", [ClimbText.Summary] = "{0} records | {1} summits", [ClimbText.Hint] = "Your local climbing history, newest first", [ClimbText.Empty] = "No climbing records yet", [ClimbText.InProgress] = "In Progress", [ClimbText.Summited] = "Summited", [ClimbText.Failed] = "Failed", [ClimbText.Abandoned] = "Abandoned", [ClimbText.Players] = "{0} player(s)", [ClimbText.Tenderfoot] = "Tenderfoot", [ClimbText.Peak] = "Peak", [ClimbText.Ascent] = "Ascent {0}", [ClimbText.NormalRun] = "Normal Mode", [ClimbText.CustomRun] = "Custom Run", [ClimbText.MiniRun] = "Mini Run", [ClimbText.Delete] = "Delete", [ClimbText.SaveMapSettings] = "Export", [ClimbText.LoadMapSettings] = "Load", [ClimbText.TerrainSeed] = "TerrainRandomiser", [ClimbText.OfflineMode] = "Offline Mode", [ClimbText.MultiplayerMode] = "Multiplayer", [ClimbText.TombOpen] = "Tomb Open", [ClimbText.TombClosed] = "Tomb Closed" }; private static readonly IReadOnlyDictionary> Translations = new Dictionary> { [(Language)9] = new Dictionary { [ClimbText.Button] = "攀爬记录", [ClimbText.Title] = "攀爬记录", [ClimbText.Summary] = "共 {0} 次 | 登顶 {1} 次", [ClimbText.Hint] = "本地玩家的攀爬历史,按时间从新到旧排列", [ClimbText.Empty] = "还没有攀爬记录", [ClimbText.InProgress] = "进行中", [ClimbText.Summited] = "已登顶", [ClimbText.Failed] = "未登顶", [ClimbText.Abandoned] = "已中止", [ClimbText.Players] = "{0} 名玩家", [ClimbText.Tenderfoot] = "菜鸟新人", [ClimbText.Peak] = "顶峰", [ClimbText.Ascent] = "天阶 {0}", [ClimbText.NormalRun] = "正常模式", [ClimbText.CustomRun] = "自定义模式", [ClimbText.MiniRun] = "速通局", [ClimbText.Delete] = "删除", [ClimbText.SaveMapSettings] = "导出", [ClimbText.LoadMapSettings] = "读取", [ClimbText.TerrainSeed] = "随机地形", [ClimbText.OfflineMode] = "离线模式", [ClimbText.MultiplayerMode] = "多人模式", [ClimbText.TombOpen] = "古墓开放", [ClimbText.TombClosed] = "古墓关闭" } }; internal static CultureInfo CurrentCulture { get { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 Language cURRENT_LANGUAGE = LocalizedText.CURRENT_LANGUAGE; if ((int)cURRENT_LANGUAGE == 9) { return GetCulture("zh-CN"); } return CultureInfo.InvariantCulture; } } internal static string Get(ClimbText key) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (Translations.TryGetValue(LocalizedText.CURRENT_LANGUAGE, out IReadOnlyDictionary value) && value.TryGetValue(key, out var value2)) { return value2; } return English[key]; } internal static string Format(ClimbText key, params object[] arguments) { return string.Format(CurrentCulture, Get(key), arguments); } internal static string GetOutcome(string outcome) { return outcome switch { "InProgress" => Get(ClimbText.InProgress), "Summited" => Get(ClimbText.Summited), "Failed" => Get(ClimbText.Failed), _ => Get(ClimbText.Abandoned), }; } private static CultureInfo GetCulture(string name) { try { return CultureInfo.GetCultureInfo(name); } catch (CultureNotFoundException) { return CultureInfo.InvariantCulture; } } } internal sealed class ClimbTracker : IDisposable { private const string AirportScene = "Airport"; private const float TerrainRandomiserCaptureDelaySeconds = 5f; private readonly ClimbHistory _history; private bool _activeInThisProcess; private bool _localPlayerSummited; private bool _delayedTerrainRandomiserCaptureAttempted; private bool _uiTerrainRandomiserCaptureAttempted; private bool _preserveActiveRunId; private float _nextSnapshotTime; internal ClimbTracker(ClimbHistory history) { _history = history; GlobalEvents.OnLocalCharacterWonRun = (Action)Delegate.Combine(GlobalEvents.OnLocalCharacterWonRun, new Action(OnLocalCharacterWonRun)); GlobalEvents.OnRunEnded = (Action)Delegate.Combine(GlobalEvents.OnRunEnded, new Action(OnRunEnded)); SceneManager.sceneLoaded += OnSceneLoaded; } internal void BeginRun() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!PluginConfig.EnableTracker.Value || _activeInThisProcess) { return; } Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name == "Airport") { return; } RunManager instance = RunManager.Instance; float elapsedSeconds = GetElapsedSeconds(instance); (string NetworkMode, string PhotonRoomName) networkState = GetNetworkState(); string item = networkState.NetworkMode; string item2 = networkState.PhotonRoomName; string text = (((Object)(object)instance != (Object)null && instance.RunId != Guid.Empty) ? instance.RunId.ToString("D") : Guid.NewGuid().ToString("D")); ClimbRecord activeRecord = _history.ActiveRecord; if (activeRecord != null && activeRecord.RunId == text) { _activeInThisProcess = true; _localPlayerSummited = false; _delayedTerrainRandomiserCaptureAttempted = false; _uiTerrainRandomiserCaptureAttempted = false; _preserveActiveRunId = false; ScheduleNextSnapshot(); return; } ClimbRecord climbRecord = new ClimbRecord { RunId = text, StartedAtUtc = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromSeconds(elapsedSeconds)).ToString("O", CultureInfo.InvariantCulture), Outcome = "InProgress", DurationSeconds = elapsedSeconds, CurrentHeightMeters = GetCurrentHeightMeters(), Ascent = Ascents.currentAscent, PlayerCount = GetPlayerCount(), IsCustomRun = RunSettings.IsCustomRun, IsMiniRun = RunSettings.isMiniRun, Level = GetLevelName(), Biome = GetBiomeName(), NetworkMode = item, PhotonRoomName = item2, MapBiomes = CaptureCurrentMapBiomes() }; bool flag = _history.TryResumeMultiplayerRoom(climbRecord); if (!flag) { _history.Begin(climbRecord); } _activeInThisProcess = true; _localPlayerSummited = false; _delayedTerrainRandomiserCaptureAttempted = false; _uiTerrainRandomiserCaptureAttempted = false; _preserveActiveRunId = flag; ScheduleNextSnapshot(); Plugin.Logger.LogInfo((object)(flag ? ("Resumed climb tracking from Photon room record. room=" + item2 + ", runId=" + _history.ActiveRecord?.RunId + ".") : ("Started tracking climb " + text + "."))); } internal void Update() { if (_activeInThisProcess) { float elapsedSeconds = GetElapsedSeconds(RunManager.Instance); TryCaptureDelayedTerrainRandomiserMapSettings(elapsedSeconds); float value = PluginConfig.AutoSaveInterval.Value; if (value <= 0f) { _nextSnapshotTime = 0f; } else if (_nextSnapshotTime <= 0f) { _nextSnapshotTime = Time.unscaledTime + value; } else if (!(Time.unscaledTime < _nextSnapshotTime)) { _history.Snapshot(elapsedSeconds, GetCurrentHeightMeters(), GetBiomeName(), GetPlayerCount(), GetNetworkMode(), GetPhotonRoomName()); TryCaptureActiveMapBiomes(); _nextSnapshotTime = Time.unscaledTime + value; } } } internal void SnapshotActiveRun() { if (_activeInThisProcess && _history.ActiveRecord != null) { float elapsedSeconds = GetElapsedSeconds(RunManager.Instance); _history.Snapshot(elapsedSeconds, GetCurrentHeightMeters(), GetBiomeName(), GetPlayerCount(), GetNetworkMode(), GetPhotonRoomName()); TryCaptureActiveMapBiomes(); TryCaptureUiTerrainRandomiserMapSettings(elapsedSeconds); } } internal void UpdateRunId(Guid runId) { if (_activeInThisProcess && !_preserveActiveRunId && runId != Guid.Empty) { _history.UpdateActiveRunId(runId.ToString("D")); } } internal void AbandonActiveRun() { CompleteActiveRun("Abandoned"); } internal void DeleteRecord(string runId) { bool flag = _history.ActiveRecord?.RunId == runId; if (_history.DeleteRecord(runId) && flag) { _activeInThisProcess = false; _localPlayerSummited = false; _delayedTerrainRandomiserCaptureAttempted = false; _uiTerrainRandomiserCaptureAttempted = false; _preserveActiveRunId = false; _nextSnapshotTime = 0f; } } internal void Dispose() { GlobalEvents.OnLocalCharacterWonRun = (Action)Delegate.Remove(GlobalEvents.OnLocalCharacterWonRun, new Action(OnLocalCharacterWonRun)); GlobalEvents.OnRunEnded = (Action)Delegate.Remove(GlobalEvents.OnRunEnded, new Action(OnRunEnded)); SceneManager.sceneLoaded -= OnSceneLoaded; CompleteActiveRun("Abandoned"); } private void OnLocalCharacterWonRun() { _localPlayerSummited = true; } private void OnRunEnded() { if (!_activeInThisProcess) { BeginRun(); } CharacterStats val = Character.localCharacter?.refs?.stats; string outcome = ((_localPlayerSummited || ((Object)(object)val != (Object)null && val.won)) ? "Summited" : "Failed"); CompleteActiveRun(outcome); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (!(((Scene)(ref scene)).name != "Airport")) { if (_activeInThisProcess) { CompleteActiveRun("Abandoned"); } else { _history.RecoverInterrupted(); } } } private void CompleteActiveRun(string outcome) { if (_history.ActiveRecord != null) { float elapsedSeconds = GetElapsedSeconds(RunManager.Instance); TryCaptureActiveMapBiomes(); _history.Complete(outcome, elapsedSeconds, GetCurrentHeightMeters(), GetBiomeName(), GetPlayerCount(), GetNetworkMode(), GetPhotonRoomName()); _activeInThisProcess = false; _localPlayerSummited = false; _delayedTerrainRandomiserCaptureAttempted = false; _uiTerrainRandomiserCaptureAttempted = false; _preserveActiveRunId = false; Plugin.Logger.LogInfo((object)("Recorded climb result: " + outcome + ".")); } } private void TryCaptureDelayedTerrainRandomiserMapSettings(float elapsedSeconds) { if (!_delayedTerrainRandomiserCaptureAttempted && !(elapsedSeconds < 5f)) { _delayedTerrainRandomiserCaptureAttempted = true; ClimbRecord activeRecord = _history.ActiveRecord; if (activeRecord != null && string.IsNullOrWhiteSpace(activeRecord.TerrainRandomiserMapSettingsBrotliBase64)) { TryCaptureTerrainRandomiserMapSettings("delayed", elapsedSeconds); } } } private void TryCaptureUiTerrainRandomiserMapSettings(float elapsedSeconds) { if (!_uiTerrainRandomiserCaptureAttempted) { _uiTerrainRandomiserCaptureAttempted = true; ClimbRecord activeRecord = _history.ActiveRecord; if (activeRecord != null && string.IsNullOrWhiteSpace(activeRecord.TerrainRandomiserMapSettingsBrotliBase64)) { TryCaptureTerrainRandomiserMapSettings("ui", elapsedSeconds); } } } private bool TryCaptureTerrainRandomiserMapSettings(string trigger, float elapsedSeconds) { ClimbRecord activeRecord = _history.ActiveRecord; if (activeRecord == null || !string.IsNullOrWhiteSpace(activeRecord.TerrainRandomiserMapSettingsBrotliBase64) || !TerrainRandomiserCompatibility.Loaded) { return false; } MapSettings mapSettings = TerrainRandomiserCompatibility.GetMapSettings(); if (!TerrainRandomiserCompatibility.IsRandomiserEnabled(mapSettings)) { return false; } string text = ((mapSettings != null) ? TerrainRandomiserCompatibility.CompressMapSettings(mapSettings) : ""); if (string.IsNullOrWhiteSpace(text)) { return false; } _history.UpdateActiveTerrainRandomiser(enabled: true, TerrainRandomiserCompatibility.GetMapSeed(mapSettings), text); Plugin.Logger.LogInfo((object)("Captured TerrainRandomiser map settings for active climb. trigger=" + trigger + ", elapsedSeconds=" + elapsedSeconds.ToString("0.##", CultureInfo.InvariantCulture) + ".")); return true; } private void TryCaptureActiveMapBiomes() { ClimbRecord activeRecord = _history.ActiveRecord; if (activeRecord != null && (activeRecord.MapBiomes == null || activeRecord.MapBiomes.Count <= 0)) { _history.EnsureActiveMapBiomes(CaptureCurrentMapBiomes()); } } private static List CaptureCurrentMapBiomes() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return new List(MapBiomeCollector.Capture(SceneManager.GetActiveScene())); } private static float GetElapsedSeconds(RunManager? runManager) { if (!((Object)(object)runManager != (Object)null)) { return 0f; } return Math.Max(0f, runManager.timeSinceRunStarted); } private void ScheduleNextSnapshot() { float value = PluginConfig.AutoSaveInterval.Value; _nextSnapshotTime = ((value > 0f) ? (Time.unscaledTime + value) : 0f); } private static float GetCurrentHeightMeters() { CharacterStats val = Character.localCharacter?.refs?.stats; if (!((Object)(object)val != (Object)null)) { return 0f; } return Math.Max(0f, val.heightInMeters); } private static int GetPlayerCount() { if (!PhotonNetwork.InRoom) { return 1; } Room currentRoom = PhotonNetwork.CurrentRoom; return Math.Max(1, (currentRoom == null) ? 1 : currentRoom.PlayerCount); } private static (string NetworkMode, string PhotonRoomName) GetNetworkState() { string networkMode = GetNetworkMode(); return (NetworkMode: networkMode, PhotonRoomName: (networkMode == "Multiplayer") ? GetPhotonRoomName() : ""); } private static string GetNetworkMode() { if (PhotonNetwork.OfflineMode) { return "Offline"; } if (!PhotonNetwork.InRoom) { return ""; } return "Multiplayer"; } private static string GetPhotonRoomName() { if (!PhotonNetwork.InRoom) { return ""; } Room currentRoom = PhotonNetwork.CurrentRoom; return ((currentRoom != null) ? currentRoom.Name : null) ?? ""; } private static string GetLevelName() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; int num = LevelNameToIndex(name); if (num == -1) { return name; } return GetLevelName(num); } private static string GetBiomeName() { try { MountainProgressHandler instance = Singleton.Instance; if ((Object)(object)instance == (Object)null) { return ""; } ProgressPoint[] progressPoints = instance.progressPoints; if (progressPoints == null || progressPoints.Length == 0) { return ""; } int num = Mathf.Clamp(instance.maxProgressPointReached, 0, progressPoints.Length - 1); return progressPoints[num].title; } catch (Exception ex) { Plugin.Logger.LogDebug((object)("Failed to resolve current biome: " + ex.Message)); return ""; } } private static string GetLevelName(int levelIndex) { levelIndex %= SingletonAsset.Instance.ScenePaths.Length; return PathUtil.WithoutExtensions(PathUtil.GetFileName(SingletonAsset.Instance.ScenePaths[levelIndex])); } private static int LevelNameToIndex(string levelName) { for (int i = 0; i < SingletonAsset.Instance.ScenePaths.Length; i++) { string levelName2 = GetLevelName(i); if (string.Equals(levelName2, levelName, StringComparison.OrdinalIgnoreCase)) { return i; } } return -1; } void IDisposable.Dispose() { Dispose(); } } [HarmonyPatch(typeof(RunManager), "StartRun")] internal static class RunManagerStartRunPatch { [HarmonyPostfix] private static void Postfix() { Plugin.Tracker.BeginRun(); } } [HarmonyPatch(typeof(RunManager), "SetRunIdForLobby")] internal static class RunManagerSetRunIdPatch { [HarmonyPostfix] private static void Postfix(Guid guid) { Plugin.Tracker.UpdateRunId(guid); } } [HarmonyPatch(typeof(RunManager), "RPC_ReceiveRunId")] internal static class RunManagerReceiveRunIdPatch { [HarmonyPostfix] private static void Postfix(RunManager __instance) { Plugin.Tracker.UpdateRunId(__instance.RunId); } } [HarmonyPatch(typeof(Player), "LeaveCurrentGame")] internal static class PlayerLeaveCurrentGamePatch { [HarmonyPrefix] private static void Prefix() { Plugin.Tracker.AbandonActiveRun(); } } internal static class MapBiomeCollector { private static readonly HashSet RootsIgnoreInVariant = new HashSet { "Redwoods", "Redwood", "Variant" }; internal static IReadOnlyList Capture(Scene scene) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) List list = new List(); try { GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects(); Biome val2 = default(Biome); for (int i = 0; i < ((Scene)(ref scene)).rootCount && i < rootGameObjects.Length; i++) { GameObject val = rootGameObjects[i]; if (((Object)val).name != "Map") { continue; } for (int j = 0; j < val.transform.childCount; j++) { Transform child = val.transform.GetChild(j); for (int k = 0; k < child.childCount; k++) { GameObject gameObject = ((Component)child.GetChild(k)).gameObject; if (gameObject.activeInHierarchy && gameObject.TryGetComponent(ref val2)) { MapBiomeInfo obj = new MapBiomeInfo { BiomeType = val2.biomeType }; Component? obj2 = FindVariant(val2); obj.Variant = CleanVariant(((obj2 != null) ? ((Object)obj2).name : null) ?? "", val2.biomeType); obj.OpenTomb = CheckOpenTomb(val2) == true; list.Add(obj); } } } break; } } catch (Exception arg) { Plugin.Logger.LogDebug((object)$"Failed to collect map biome information: {arg}"); } return list; } private static Component? FindVariant(Biome biome) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected I4, but got Unknown BiomeType biomeType = biome.biomeType; switch ((int)biomeType) { case 6: case 7: return ((Component)biome).gameObject.GetComponentInChildrenActiveSelf(); case 0: case 1: case 2: return ((Component)biome).gameObject.GetComponentInChildrenActiveSelf(); case 3: case 5: case 8: return null; default: return ((Component)biome).gameObject.GetComponentInChildrenActiveSelf() ?? ((Component)biome).gameObject.GetComponentInChildrenActiveSelf(); } } private static bool? CheckOpenTomb(Biome biome) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)biome.biomeType != 6) { return null; } Transform val = ((Component)biome).transform.QueryChildren("Desert_Segment/Platteau/Rocks/Timple/Enterences/2"); Transform val2 = (((Object)(object)val != (Object)null && val.childCount > 0) ? val.GetChild(0) : null); return (Object)(object)val2 != (Object)null && val2.childCount == 2; } private static string CleanVariant(string variant, BiomeType biome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)biome != 6) { if ((int)biome == 7) { return CleanRootsVariant(variant); } return variant; } return CleanMesaVariant(variant); } private static string CleanMesaVariant(string variant) { if (variant.Equals("NoVariant", StringComparison.Ordinal)) { return "Default"; } if (variant.Equals("CacusHell", StringComparison.Ordinal)) { return "CactusHell"; } return variant; } private static string CleanRootsVariant(string variant) { string[] array = variant.Split(' ', '-'); if (array.Length <= 1) { return variant; } for (int i = 0; i < array.Length; i++) { string text = array[i]; if (text.Length > 0) { text = text.Substring(0, 1).ToUpperInvariant() + text.Substring(1).ToLowerInvariant(); } if (RootsIgnoreInVariant.Contains(text)) { text = ""; } array[i] = text; } return string.Join("", array); } private static Component? GetComponentInChildrenActiveSelf(this GameObject gameObject) where T : Component { Component[] componentsInChildren = (Component[])(object)gameObject.GetComponentsInChildren(true); Component[] array = componentsInChildren; Component[] array2 = array; foreach (Component val in array2) { if (val.gameObject.activeSelf) { return val; } } return null; } private static Transform? QueryChildren(this Transform current, string queryOrPath) { string[] array = queryOrPath.Split('/'); string[] array2 = array; foreach (string text in array2) { Transform val = current.Find(text); if ((Object)(object)val == (Object)null) { return null; } current = val; } return current; } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.github.LengSword.ClimbInfoTracker", "ClimbInfoTracker", "0.1.3")] public class Plugin : BaseUnityPlugin { public const string Id = "com.github.LengSword.ClimbInfoTracker"; internal static ManualLogSource Logger { get; private set; } internal static ClimbHistory History { get; private set; } internal static ClimbTracker Tracker { get; private set; } public static string Name => "ClimbInfoTracker"; public static string Version => "0.1.3"; private void Awake() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)("Plugin " + Name + " is loaded!")); PluginConfig.Initialize(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); History = new ClimbHistory(); Tracker = new ClimbTracker(History); Harmony val = new Harmony("com.github.LengSword.ClimbInfoTracker"); val.PatchAll(); } private void Start() { ClimbHistoryUi.Register(); } private void Update() { Tracker.Update(); } private void OnDestroy() { ClimbHistoryUi.Dispose(); Tracker.Dispose(); } } public static class PluginConfig { internal static ConfigEntry EnableTracker { get; private set; } internal static ConfigEntry AutoSaveInterval { get; private set; } internal static ConfigEntry UseActualMapSettings { get; private set; } public static void Initialize(ConfigFile config, ManualLogSource logger) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown EnableTracker = config.Bind("General", "Enable Tracker", true, "Enable or disable recording new climb history."); AutoSaveInterval = config.Bind("General", "AutoSaveInterval", 60f, new ConfigDescription("Seconds between in-progress climb snapshots. Set to 0 to save only at the start and end of a climb.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, float.MaxValue), Array.Empty())); UseActualMapSettings = config.Bind("TerrainRandomiser", "UseActualMapSettings", true, "When loading TerrainRandomiser map settings from climb records, use the final generated settings by disabling randomBiome and randomVariant for overridden biomes."); logger.LogInfo((object)"Plugin Config Loaded."); } } [Serializable] internal class MapSettings { public bool enableRandomiser; public int seed; public bool autoRandomSeed; public bool fullyRandom; public List biomes = new List(); } [Serializable] internal class BiomeSettings { public bool overrideEnabled; public string sectionName = ""; public BiomeData selectedBiome = new BiomeData(); public string selectedVariant = ""; public bool randomBiome; public bool randomVariant; } [Serializable] internal class BiomeData { public string biomeName = ""; public BiomeType biomeType; public List variants = new List(); public VariantSelectionType variantSelectionType; } public enum VariantSelectionType { BiomeVariant, VariantObject } internal static class TerrainRandomiserCompatibility { internal static bool Loaded => Chainloader.PluginInfos.ContainsKey("com.snosz.terrainrandomiser"); internal static MapSettings? GetMapSettings() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!Loaded) { return null; } if (PhotonNetwork.OfflineMode) { return GetLocalMapSettingsNoInlining(); } try { SteamLobbyHandler service = GameHandler.GetService(); string lobbyData = SteamMatchmaking.GetLobbyData(service.LobbySteamId, "TR_roomMapSettings"); return string.IsNullOrWhiteSpace(lobbyData) ? null : JsonConvert.DeserializeObject(lobbyData); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Failed to read TerrainRandomiser lobby map settings: {arg}"); return null; } } [MethodImpl(MethodImplOptions.NoInlining)] private static MapSettings? GetLocalMapSettingsNoInlining() { try { MapSettings val = Plugin.Instance?.mapSettings; if (val == null) { return null; } string text = JsonConvert.SerializeObject((object)val); return JsonConvert.DeserializeObject(text); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Failed to read local TerrainRandomiser map settings: {arg}"); return null; } } internal static bool IsRandomiserEnabled(MapSettings? mapSettings) { return mapSettings?.enableRandomiser ?? false; } internal static int GetMapSeed(MapSettings? mapSettings) { return mapSettings?.seed ?? (-1); } internal static string CompressMapSettings(MapSettings mapSettings) { try { string s = JsonConvert.SerializeObject((object)mapSettings, (Formatting)0); byte[] bytes = Encoding.UTF8.GetBytes(s); using MemoryStream memoryStream = new MemoryStream(); using (BrotliStream brotliStream = new BrotliStream(memoryStream, CompressionLevel.Optimal, leaveOpen: true)) { brotliStream.Write(bytes, 0, bytes.Length); } return Convert.ToBase64String(memoryStream.ToArray()); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Failed to compress TerrainRandomiser map settings: {arg}"); return ""; } } internal static MapSettings? DecompressMapSettings(string compressedMapSettings) { if (string.IsNullOrWhiteSpace(compressedMapSettings)) { return null; } try { byte[] buffer = Convert.FromBase64String(compressedMapSettings); using MemoryStream stream = new MemoryStream(buffer); using BrotliStream brotliStream = new BrotliStream(stream, CompressionMode.Decompress); using MemoryStream memoryStream = new MemoryStream(); brotliStream.CopyTo(memoryStream); string text = Encoding.UTF8.GetString(memoryStream.ToArray()); return JsonConvert.DeserializeObject(text); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Failed to decompress TerrainRandomiser map settings: {arg}"); return null; } } internal static string? SaveMapSettings(string compressedMapSettings, string startedAtUtc) { MapSettings mapSettings = DecompressMapSettings(compressedMapSettings); if (mapSettings == null) { return null; } try { string text = Path.Combine(Application.persistentDataPath, "TerrainRandomiser"); Directory.CreateDirectory(text); string text2 = FormatStartedAtTimestamp(startedAtUtc); string text3 = Path.Combine(text, "MapSettings_" + text2 + ".json"); string contents = JsonConvert.SerializeObject((object)mapSettings, (Formatting)1); File.WriteAllText(text3, contents, Encoding.UTF8); return text3; } catch (Exception arg) { Plugin.Logger.LogError((object)$"Failed to save TerrainRandomiser map settings: {arg}"); return null; } } internal static bool LoadMapSettings(string compressedMapSettings) { MapSettings mapSettings = DecompressMapSettings(compressedMapSettings); if (mapSettings == null) { return false; } try { if (PluginConfig.UseActualMapSettings.Value) { ApplyActualGeneratedMapSettings(mapSettings); } return LoadMapSettingsNoInlining(mapSettings); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Failed to load TerrainRandomiser map settings: {arg}"); return false; } } [MethodImpl(MethodImplOptions.NoInlining)] private static bool LoadMapSettingsNoInlining(MapSettings mapSettings) { Plugin instance = Plugin.Instance; if ((Object)(object)instance == (Object)null) { Plugin.Logger.LogError((object)"Failed to load TerrainRandomiser map settings: plugin missing."); return false; } string text = JsonConvert.SerializeObject((object)mapSettings); MapSettings val = JsonConvert.DeserializeObject(text); if (val == null) { Plugin.Logger.LogError((object)"Failed to convert local map settings to TerrainRandomiser map settings."); return false; } instance.mapSettings = val; return true; } private static void ApplyActualGeneratedMapSettings(MapSettings mapSettings) { if (mapSettings.biomes == null) { return; } foreach (BiomeSettings biome in mapSettings.biomes) { if (biome.overrideEnabled) { biome.randomBiome = false; biome.randomVariant = false; } } } private static string FormatStartedAtTimestamp(string startedAtUtc) { if (DateTimeOffset.TryParse(startedAtUtc, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var result)) { return result.ToLocalTime().ToString("yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture); } if (string.IsNullOrWhiteSpace(startedAtUtc)) { return "UnknownStart"; } StringBuilder stringBuilder = new StringBuilder(startedAtUtc.Length); foreach (char c in startedAtUtc) { stringBuilder.Append((Array.IndexOf(Path.GetInvalidFileNameChars(), c) >= 0) ? '-' : c); } return stringBuilder.ToString(); } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SkipLocalsInitAttribute : Attribute { } }