Decompiled source of FriendBPSort v1.0.0

FriendBPSort.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.RegularExpressions;
using FriendBPSort;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppRUMBLE.Interactions.InteractionBase;
using Il2CppRUMBLE.Players;
using Il2CppRUMBLE.Social;
using Il2CppRUMBLE.Social.Phone;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(/*Could not decode attribute arguments.*/)]
[assembly: MelonInfo(typeof(Mod), "FriendBPSort", "0.2.3", "Colli", null)]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : System.Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(/*Could not decode attribute arguments.*/)]
	internal sealed class RefSafetyRulesAttribute : System.Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FriendBPSort
{
	public sealed class Mod : MelonMod
	{
		private sealed class SideButton
		{
			internal GameObject Object;

			internal TMP_Text Label;

			internal SortMode Mode;

			internal bool? Selected;
		}

		private static readonly Dictionary<int, FriendList> lists = new Dictionary<int, FriendList>();

		private static readonly Dictionary<int, List<SideButton>> controls = new Dictionary<int, List<SideButton>>();

		private static readonly Dictionary<string, int> points = new Dictionary<string, int>((IEqualityComparer<string>)(object)StringComparer.Ordinal);

		private static readonly string[] captions = new string[4] { "SORT A–Z", "SORT BY BP", "FRIEND ADDED", "RECENTLY PLAYED" };

		private static SortHistory history = new SortHistory();

		private static SortMode mode;

		private static MelonPreferences_Category preferences;

		private static MelonPreferences_Entry<int> savedMode;

		private static MelonPreferences_Entry<string> savedHistory;

		private static bool dirty;

		private static bool historyDirty;

		private static bool stopped;

		private static bool warnedMissingAsset;

		private static bool resetPage;

		private static float nextTick;

		private static float nextAssetSearch;

		private static float nextSave;

		private static GameObject staging;

		private static Material backboardMaterial;

		private static InteractionButton stoneButton;

		private static bool rendering;

		private static string Key(UserSearchResult f)
		{
			object obj;
			if (string.IsNullOrWhiteSpace((f != null) ? f.PlayFabMasterId : null))
			{
				obj = ((f != null) ? f.PlayFabTitleId : null);
				if (obj == null)
				{
					return "";
				}
			}
			else
			{
				obj = f.PlayFabMasterId;
			}
			return (string)obj;
		}

		private static string Key(UserData u)
		{
			object obj;
			if (string.IsNullOrWhiteSpace((u != null) ? u.playFabMasterId : null))
			{
				obj = ((u != null) ? u.playFabTitleId : null);
				if (obj == null)
				{
					return "";
				}
			}
			else
			{
				obj = u.playFabMasterId;
			}
			return (string)obj;
		}

		private static int BP(UserSearchResult f)
		{
			int result = default(int);
			if (!points.TryGetValue(Key(f), ref result))
			{
				return -1;
			}
			return result;
		}

		public override void OnInitializeMelon()
		{
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Expected O, but got Unknown
			preferences = MelonPreferences.CreateCategory("FriendBPSort");
			savedMode = preferences.CreateEntry<int>("SortMode", 0, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			savedHistory = preferences.CreateEntry<string>("SortHistory", "", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			mode = (System.Enum.IsDefined(typeof(SortMode), (object)savedMode.Value) ? ((SortMode)savedMode.Value) : SortMode.Alphabetical);
			if (!string.IsNullOrWhiteSpace(savedHistory.Value))
			{
				try
				{
					history = JsonSerializer.Deserialize<SortHistory>(savedHistory.Value, (JsonSerializerOptions)null) ?? new SortHistory();
					SortHistory sortHistory = history;
					if (sortHistory.KnownFriends == null)
					{
						HashSet<string> val = (sortHistory.KnownFriends = new HashSet<string>());
					}
					sortHistory = history;
					if (sortHistory.Added == null)
					{
						Dictionary<string, long> val3 = (sortHistory.Added = new Dictionary<string, long>());
					}
					sortHistory = history;
					if (sortHistory.Played == null)
					{
						Dictionary<string, long> val3 = (sortHistory.Played = new Dictionary<string, long>());
					}
				}
				catch (System.Exception ex)
				{
					MelonLogger.Warning("\ud83d\udc31 Sort history could not be read: " + ex.Message);
					history = new SortHistory();
				}
			}
			BindingFlags val6 = (BindingFlags)40;
			((MelonBase)this).HarmonyInstance.Patch((MethodBase)(object)typeof(FriendList).GetMethod("Refresh"), new HarmonyMethod(typeof(Mod).GetMethod("RefreshUnified", val6)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((MelonBase)this).HarmonyInstance.Patch((MethodBase)(object)typeof(FriendHandler).GetMethod("AddRecentlyMetPlayer"), (HarmonyMethod)null, new HarmonyMethod(typeof(Mod).GetMethod("MetPlayer", val6)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			MelonLogger.Msg("FriendBPSort: four physical sort buttons ready. Historical friend dates are unknown; new additions and encounters are tracked locally.");
		}

		private static bool Snapshot()
		{
			bool result = false;
			List<UserData> userDataList = UserDataManager.userDataList;
			if (userDataList != null)
			{
				Enumerator<UserData> enumerator = userDataList.GetEnumerator();
				int num = default(int);
				while (enumerator.MoveNext())
				{
					UserData current = enumerator.Current;
					if (current != null && current.battlePoints >= 0)
					{
						string text = Key(current);
						if (text.Length != 0 && (!points.TryGetValue(text, ref num) || num != current.battlePoints))
						{
							points[text] = current.battlePoints;
							result = true;
						}
					}
				}
			}
			return result;
		}

		private static int CompareFriends(GetFriendsResult a, GetFriendsResult b)
		{
			return Ranking.Compare(mode, BP((UserSearchResult)(object)a), (a != null) ? ((UserSearchResult)a).PublicName : null, Key((UserSearchResult)(object)a), history.Date(mode, (a != null) ? ((UserSearchResult)a).PlayFabMasterId : null, (a != null) ? ((UserSearchResult)a).PlayFabTitleId : null), BP((UserSearchResult)(object)b), (b != null) ? ((UserSearchResult)b).PublicName : null, Key((UserSearchResult)(object)b), history.Date(mode, (b != null) ? ((UserSearchResult)b).PlayFabMasterId : null, (b != null) ? ((UserSearchResult)b).PlayFabTitleId : null));
		}

		private static bool RefreshUnified(FriendList __instance)
		{
			if (rendering)
			{
				return false;
			}
			lists[((Object)__instance).GetInstanceID()] = __instance;
			Il2CppReferenceArray<ScrollableItem> scrollableItems = ((ScrollableList)__instance).ScrollableItems;
			if (scrollableItems == null)
			{
				return true;
			}
			if (Enumerable.Any<ScrollableItem>((System.Collections.Generic.IEnumerable<ScrollableItem>)scrollableItems, (Func<ScrollableItem, bool>)delegate(ScrollableItem item)
			{
				if (item == null)
				{
					return false;
				}
				PlayerTag obj2 = ((Il2CppObjectBase)item).TryCast<PlayerTag>();
				return ((obj2 != null) ? new bool?(obj2.isInitializing) : ((bool?)null)) == true;
			}))
			{
				dirty = true;
				return false;
			}
			rendering = true;
			try
			{
				Snapshot();
				List<GetFriendsResult> friendsWithTag = FriendHandler.GetFriendsWithTag(__instance.listeningToTags);
				if (friendsWithTag == null)
				{
					return true;
				}
				List<GetFriendsResult> val = new List<GetFriendsResult>();
				Enumerator<GetFriendsResult> enumerator = friendsWithTag.GetEnumerator();
				while (enumerator.MoveNext())
				{
					GetFriendsResult current = enumerator.Current;
					if (current != null)
					{
						val.Add(current);
					}
				}
				val.Sort((Comparison<GetFriendsResult>)CompareFriends);
				((ScrollableList)__instance).SetListSize(val.Count);
				((ScrollableList)__instance).topItemNo = Math.Max(0, Math.Min(((ScrollableList)__instance).topItemNo, Math.Max(0, val.Count - ((Il2CppArrayBase<ScrollableItem>)(object)scrollableItems).Length)));
				for (int num = 0; num < ((Il2CppArrayBase<ScrollableItem>)(object)scrollableItems).Length; num++)
				{
					ScrollableItem obj = ((Il2CppArrayBase<ScrollableItem>)(object)scrollableItems)[num];
					PlayerTag val2 = ((obj != null) ? ((Il2CppObjectBase)obj).TryCast<PlayerTag>() : null);
					if (Object.op_Implicit((Object)(object)val2))
					{
						int num2 = ((ScrollableList)__instance).topItemNo + num;
						bool flag = num2 < val.Count;
						if (((Component)val2).gameObject.activeSelf != flag)
						{
							((Component)val2).gameObject.SetActive(flag);
						}
						if (flag)
						{
							val2.Initialize((UserSearchResult)(object)val[num2], Action<bool>.op_Implicit((Action<bool>)delegate
							{
							}));
						}
					}
				}
				return false;
			}
			catch (System.Exception ex)
			{
				MelonLogger.Warning("\ud83d\udc31 Unified friend sort failed: " + ex.GetBaseException().Message);
				return true;
			}
			finally
			{
				rendering = false;
			}
		}

		private static void MetPlayer(string __0)
		{
			if (!string.IsNullOrWhiteSpace(__0))
			{
				history.RecordPlayed(__0, System.DateTime.UtcNow.Ticks);
				historyDirty = true;
				if (mode == SortMode.RecentlyPlayed)
				{
					dirty = true;
				}
			}
		}

		private static void Choose(SortMode chosen)
		{
			if (mode != chosen)
			{
				mode = chosen;
				savedMode.Value = (int)mode;
				dirty = true;
				historyDirty = true;
				resetPage = true;
			}
		}

		private static void Save()
		{
			try
			{
				savedHistory.Value = JsonSerializer.Serialize<SortHistory>(history, (JsonSerializerOptions)null);
				preferences.SaveToFile(false);
				historyDirty = false;
			}
			catch (System.Exception ex)
			{
				MelonLogger.Warning("\ud83d\udc31 Could not save sorting preferences: " + ex.Message);
			}
		}

		public override void OnUpdate()
		{
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			if (stopped || Time.unscaledTime < nextTick)
			{
				return;
			}
			nextTick = Time.unscaledTime + 0.5f;
			try
			{
				if (Snapshot() && mode == SortMode.BattlePoints)
				{
					dirty = true;
				}
				List<GetFriendsResult> confirmedFriends = FriendHandler.ConfirmedFriends;
				if (confirmedFriends != null)
				{
					List<string> val = new List<string>();
					Enumerator<GetFriendsResult> enumerator = confirmedFriends.GetEnumerator();
					while (enumerator.MoveNext())
					{
						GetFriendsResult current = enumerator.Current;
						val.Add(Key((UserSearchResult)(object)current));
					}
					if (history.ObserveFriends((System.Collections.Generic.IEnumerable<string>)val, System.DateTime.UtcNow.Ticks))
					{
						historyDirty = true;
						if (mode == SortMode.FriendAdded)
						{
							dirty = true;
						}
					}
				}
				if (historyDirty && Time.unscaledTime >= nextSave)
				{
					nextSave = Time.unscaledTime + 5f;
					Save();
				}
				int[] array = Enumerable.ToArray<int>(Enumerable.Select<KeyValuePair<int, FriendList>, int>(Enumerable.Where<KeyValuePair<int, FriendList>>((System.Collections.Generic.IEnumerable<KeyValuePair<int, FriendList>>)lists, (Func<KeyValuePair<int, FriendList>, bool>)((KeyValuePair<int, FriendList> p) => !Object.op_Implicit((Object)(object)p.Value))), (Func<KeyValuePair<int, FriendList>, int>)((KeyValuePair<int, FriendList> p) => p.Key)));
				List<SideButton> val2 = default(List<SideButton>);
				foreach (int num2 in array)
				{
					if (controls.TryGetValue(num2, ref val2))
					{
						Enumerator<SideButton> enumerator2 = val2.GetEnumerator();
						try
						{
							while (enumerator2.MoveNext())
							{
								SideButton current2 = enumerator2.Current;
								if (Object.op_Implicit((Object)(object)current2.Object))
								{
									Object.Destroy((Object)(object)current2.Object);
								}
							}
						}
						finally
						{
							((System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
						}
					}
					controls.Remove(num2);
					lists.Remove(num2);
				}
				bool flag = false;
				KeyValuePair<int, FriendList>[] array2 = Enumerable.ToArray<KeyValuePair<int, FriendList>>((System.Collections.Generic.IEnumerable<KeyValuePair<int, FriendList>>)lists);
				List<SideButton> val4 = default(List<SideButton>);
				for (int num = 0; num < array2.Length; num++)
				{
					KeyValuePair<int, FriendList> val3 = array2[num];
					FriendList value = val3.Value;
					if (!((Component)value).gameObject.activeInHierarchy)
					{
						flag |= dirty;
						continue;
					}
					Il2CppReferenceArray<ScrollableItem> scrollableItems = ((ScrollableList)value).ScrollableItems;
					if (scrollableItems == null)
					{
						flag |= dirty;
						continue;
					}
					if (dirty)
					{
						if (Enumerable.Any<ScrollableItem>((System.Collections.Generic.IEnumerable<ScrollableItem>)scrollableItems, (Func<ScrollableItem, bool>)delegate(ScrollableItem item)
						{
							if (item == null)
							{
								return false;
							}
							PlayerTag obj = ((Il2CppObjectBase)item).TryCast<PlayerTag>();
							return ((obj != null) ? new bool?(obj.isInitializing) : ((bool?)null)) == true;
						}))
						{
							flag = true;
						}
						else
						{
							if (resetPage)
							{
								((ScrollableList)value).topItemNo = 0;
							}
							((ScrollableList)value).Refresh();
						}
					}
					if (!controls.TryGetValue(val3.Key, ref val4))
					{
						val4 = (controls[val3.Key] = new List<SideButton>());
					}
					val4.RemoveAll((Predicate<SideButton>)((SideButton b) => !Object.op_Implicit((Object)(object)b.Object)));
					PlayerTag val6 = Enumerable.FirstOrDefault<PlayerTag>(Enumerable.Select<ScrollableItem, PlayerTag>((System.Collections.Generic.IEnumerable<ScrollableItem>)scrollableItems, (Func<ScrollableItem, PlayerTag>)((ScrollableItem i) => (i == null) ? null : ((Il2CppObjectBase)i).TryCast<PlayerTag>())), (Func<PlayerTag, bool>)((PlayerTag t) => Object.op_Implicit((Object)(object)t) && Object.op_Implicit((Object)(object)t.username) && Object.op_Implicit((Object)(object)t.moreInfoButton)));
					if (!Object.op_Implicit((Object)(object)val6))
					{
						continue;
					}
					foreach (SortMode choice in System.Enum.GetValues(typeof(SortMode)))
					{
						if (!Enumerable.Any<SideButton>((System.Collections.Generic.IEnumerable<SideButton>)val4, (Func<SideButton, bool>)((SideButton b) => b.Mode == choice)))
						{
							SideButton sideButton = MakeButton(val6, value, choice);
							if (sideButton != null)
							{
								val4.Add(sideButton);
							}
						}
					}
					Enumerator<SideButton> enumerator2 = val4.GetEnumerator();
					try
					{
						while (enumerator2.MoveNext())
						{
							SideButton current3 = enumerator2.Current;
							bool flag2 = current3.Mode == mode;
							if (current3.Selected != flag2)
							{
								current3.Label.text = captions[(int)current3.Mode] + (flag2 ? " ✓" : "");
								((Graphic)current3.Label).color = (Color)(flag2 ? new Color(1f, 0.8f, 0.15f) : Color.white);
								current3.Selected = flag2;
							}
						}
					}
					finally
					{
						((System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
					}
				}
				dirty = flag;
				if (!flag)
				{
					resetPage = false;
				}
			}
			catch (System.Exception ex)
			{
				MelonLogger.Warning("\ud83d\udc31 FriendBPSort: " + ex.GetBaseException().Message);
				nextTick = Time.unscaledTime + 5f;
			}
		}

		private static void ClearEvents(InteractionButton button)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			button.onPressed = new UnityEvent();
			button.onPressedByPlayer = new UnityEvent<Player>();
			button.onToggledByPlayerController = new UnityEvent<bool, PlayerController>();
			button.onToggleStateChanged = new UnityEventBool();
			button.isToggleButton = false;
			button.useLongPress = false;
			button.disableButtonAfterInit = false;
			button.pressInterval = 0.5f;
		}

		private static SideButton MakeButton(PlayerTag tag, FriendList list, SortMode choice)
		{
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: 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_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_0368: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_043d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0442: Unknown result type (might be due to invalid IL or missing references)
			//IL_044c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0451: Unknown result type (might be due to invalid IL or missing references)
			//IL_0459: Unknown result type (might be due to invalid IL or missing references)
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			//IL_046f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_040f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: 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_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_060e: Unknown result type (might be due to invalid IL or missing references)
			//IL_061e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0628: Unknown result type (might be due to invalid IL or missing references)
			//IL_062d: Unknown result type (might be due to invalid IL or missing references)
			//IL_063d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0647: Unknown result type (might be due to invalid IL or missing references)
			//IL_064c: Unknown result type (might be due to invalid IL or missing references)
			//IL_065c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0666: Unknown result type (might be due to invalid IL or missing references)
			//IL_066b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0687: Unknown result type (might be due to invalid IL or missing references)
			//IL_06af: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0706: Unknown result type (might be due to invalid IL or missing references)
			//IL_06db: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0713: Unknown result type (might be due to invalid IL or missing references)
			//IL_071a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0722: Unknown result type (might be due to invalid IL or missing references)
			//IL_0729: Unknown result type (might be due to invalid IL or missing references)
			//IL_0731: Unknown result type (might be due to invalid IL or missing references)
			//IL_0738: Unknown result type (might be due to invalid IL or missing references)
			//IL_0740: Unknown result type (might be due to invalid IL or missing references)
			//IL_0756: Unknown result type (might be due to invalid IL or missing references)
			//IL_0772: Unknown result type (might be due to invalid IL or missing references)
			//IL_0789: Unknown result type (might be due to invalid IL or missing references)
			//IL_07aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_07da: Unknown result type (might be due to invalid IL or missing references)
			//IL_07de: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0828: Unknown result type (might be due to invalid IL or missing references)
			//IL_083e: Unknown result type (might be due to invalid IL or missing references)
			//IL_084e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0858: Unknown result type (might be due to invalid IL or missing references)
			//IL_085d: Unknown result type (might be due to invalid IL or missing references)
			//IL_086d: Unknown result type (might be due to invalid IL or missing references)
			//IL_087d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0882: Unknown result type (might be due to invalid IL or missing references)
			//IL_088f: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_08c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_09cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_09d6: Expected O, but got Unknown
			//IL_0930: Unknown result type (might be due to invalid IL or missing references)
			//IL_093a: Expected O, but got Unknown
			//IL_0928: Unknown result type (might be due to invalid IL or missing references)
			//IL_097f: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a1: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)tag.moreInfoButton) || !Object.op_Implicit((Object)(object)tag.username))
			{
				return null;
			}
			if (!Object.op_Implicit((Object)(object)stoneButton) && Time.unscaledTime >= nextAssetSearch)
			{
				nextAssetSearch = Time.unscaledTime + 5f;
				System.Collections.Generic.IEnumerator<InteractionButton> enumerator = Object.FindObjectsOfType<InteractionButton>(true).GetEnumerator();
				try
				{
					while (((System.Collections.IEnumerator)enumerator).MoveNext())
					{
						InteractionButton current = enumerator.Current;
						Transform parent = ((Component)current).transform.parent;
						while (Object.op_Implicit((Object)(object)parent))
						{
							if (((Object)parent).name.IndexOf("ShiftstoneQuickswapper", (StringComparison)5) >= 0)
							{
								stoneButton = current;
								break;
							}
							parent = parent.parent;
						}
						if (Object.op_Implicit((Object)(object)stoneButton))
						{
							break;
						}
					}
				}
				finally
				{
					((System.IDisposable)enumerator)?.Dispose();
				}
				if (!Object.op_Implicit((Object)(object)stoneButton) && !warnedMissingAsset)
				{
					warnedMissingAsset = true;
					MelonLogger.Warning("\ud83d\udc31 Shiftstone quickswap button not found; favorites will appear when the asset is available.");
				}
				if (Object.op_Implicit((Object)(object)stoneButton))
				{
					warnedMissingAsset = false;
				}
			}
			if (!Object.op_Implicit((Object)(object)stoneButton))
			{
				return null;
			}
			if (!Object.op_Implicit((Object)(object)staging))
			{
				staging = new GameObject("FriendBPSort.Staging");
				staging.SetActive(false);
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)stoneButton).gameObject, staging.transform);
			((Object)val).name = "FriendBPSort.Sort." + ((object)choice/*cast due to .constrained prefix*/).ToString();
			try
			{
				val.SetActive(false);
				val.transform.SetParent(((Component)list).transform, false);
				val.transform.rotation = ((Component)tag.moreInfoButton).transform.rotation;
				Vector3 lossyScale = ((Component)list).transform.lossyScale;
				Vector3 lossyScale2 = ((Component)stoneButton).transform.lossyScale;
				if (Mathf.Abs(lossyScale.x) < 0.0001f || Mathf.Abs(lossyScale.y) < 0.0001f || Mathf.Abs(lossyScale.z) < 0.0001f)
				{
					throw new InvalidOperationException("\ud83d\udc31 Cannot place favorite button on a board with zero scale.");
				}
				val.transform.localScale = new Vector3(lossyScale2.x / lossyScale.x, lossyScale2.y / lossyScale.y, lossyScale2.z / lossyScale.z);
				Il2CppArrayBase<Renderer> componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
				if (componentsInChildren.Length > 0)
				{
					Bounds bounds = componentsInChildren[0].bounds;
					System.Collections.Generic.IEnumerator<Renderer> enumerator2 = componentsInChildren.GetEnumerator();
					try
					{
						while (((System.Collections.IEnumerator)enumerator2).MoveNext())
						{
							Renderer current2 = enumerator2.Current;
							((Bounds)(ref bounds)).Encapsulate(current2.bounds);
						}
					}
					finally
					{
						((System.IDisposable)enumerator2)?.Dispose();
					}
					float num = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z));
					if (num > 0.001f)
					{
						Transform transform = val.transform;
						transform.localScale *= 0.09f / num;
					}
				}
				Vector3 val2 = ((Component)tag).transform.InverseTransformPoint(((Component)tag.moreInfoButton).transform.position);
				float x = ((Component)tag).transform.InverseTransformPoint(tag.username.transform.position).x;
				val2.x = x - Mathf.Max(Mathf.Abs(val2.x - x), 0.06f);
				val.transform.position = ((Component)tag).transform.TransformPoint(val2) - tag.username.transform.up * (0.12f * (float)choice);
				Vector3 right = tag.username.transform.right;
				float num2 = Vector3.Dot(val.transform.position, right) - 0.18f;
				InteractionButton[] array = (InteractionButton[])(object)new InteractionButton[4]
				{
					((ScrollableList)list).pageUpButton,
					((ScrollableList)list).pageDownButton,
					((ScrollableList)list).scrollUpButton,
					((ScrollableList)list).scrollDownButton
				};
				foreach (InteractionButton val3 in array)
				{
					if (Object.op_Implicit((Object)(object)val3))
					{
						num2 = Mathf.Min(num2, Vector3.Dot(((Component)val3).transform.position, right) - 0.16f);
					}
				}
				Transform transform2 = val.transform;
				transform2.position += right * (num2 - Vector3.Dot(val.transform.position, right));
				Transform transform3 = val.transform;
				transform3.position -= right * 0.18f;
				Transform transform4 = val.transform;
				transform4.position -= tag.username.transform.forward * 0.12f;
				InteractionButton component = val.GetComponent<InteractionButton>();
				ClearEvents(component);
				component.isPressed = false;
				component.waitingForRelease = false;
				component.canBeToggledAgain = true;
				component.closestCollider = null;
				component.lastTimePressed = -100f;
				System.Collections.Generic.IEnumerator<Collider> enumerator3 = val.GetComponentsInChildren<Collider>(true).GetEnumerator();
				try
				{
					while (((System.Collections.IEnumerator)enumerator3).MoveNext())
					{
						enumerator3.Current.enabled = true;
					}
				}
				finally
				{
					((System.IDisposable)enumerator3)?.Dispose();
				}
				System.Collections.Generic.IEnumerator<Rigidbody> enumerator4 = val.GetComponentsInChildren<Rigidbody>(true).GetEnumerator();
				try
				{
					while (((System.Collections.IEnumerator)enumerator4).MoveNext())
					{
						Rigidbody current3 = enumerator4.Current;
						current3.isKinematic = true;
						current3.useGravity = false;
						current3.detectCollisions = true;
					}
				}
				finally
				{
					((System.IDisposable)enumerator4)?.Dispose();
				}
				System.Collections.Generic.IEnumerator<TMP_Text> enumerator5 = val.GetComponentsInChildren<TMP_Text>(true).GetEnumerator();
				try
				{
					while (((System.Collections.IEnumerator)enumerator5).MoveNext())
					{
						((Component)enumerator5.Current).gameObject.SetActive(false);
					}
				}
				finally
				{
					((System.IDisposable)enumerator5)?.Dispose();
				}
				TMP_Text component2 = Object.Instantiate<GameObject>(((Component)tag.username).gameObject, val.transform).GetComponent<TMP_Text>();
				((Object)component2).name = "SortLabel";
				component2.text = captions[(int)choice];
				component2.alignment = (TextAlignmentOptions)514;
				((Graphic)component2).raycastTarget = false;
				((Component)component2).gameObject.SetActive(true);
				component2.transform.position = val.transform.position - tag.username.transform.right * 0.22f - tag.username.transform.up * 0.025f - tag.username.transform.forward * 0.055f;
				component2.transform.rotation = tag.username.transform.rotation;
				component2.fontSize = tag.username.fontSize * 0.85f;
				Vector3 lossyScale3 = val.transform.lossyScale;
				Vector3 lossyScale4 = tag.username.transform.lossyScale;
				if (Mathf.Abs(lossyScale3.x) < 0.0001f || Mathf.Abs(lossyScale3.y) < 0.0001f || Mathf.Abs(lossyScale3.z) < 0.0001f)
				{
					throw new InvalidOperationException("\ud83d\udc31 Favorite button asset has zero scale.");
				}
				component2.transform.localScale = new Vector3(lossyScale4.x / lossyScale3.x, lossyScale4.y / lossyScale3.y, lossyScale4.z / lossyScale3.z);
				component2.rectTransform.sizeDelta = new Vector2(0.32f / Mathf.Max(Mathf.Abs(lossyScale4.x), 0.0001f), 0.065f / Mathf.Max(Mathf.Abs(lossyScale4.y), 0.0001f));
				component2.enableAutoSizing = false;
				component2.enableWordWrapping = false;
				float num3 = component2.GetPreferredValues("ABCDEFG").x * Mathf.Abs(component2.transform.lossyScale.x);
				Transform transform5 = component2.transform;
				transform5.position -= right * num3;
				GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3);
				obj.SetActive(false);
				((Object)obj).name = "SortButtonBackboard";
				obj.transform.SetParent(val.transform, false);
				obj.transform.rotation = tag.username.transform.rotation;
				obj.transform.position = val.transform.position + tag.username.transform.forward * 0.0396f;
				obj.transform.localScale = Vector3.one;
				Vector3 lossyScale5 = obj.transform.lossyScale;
				obj.transform.localScale = new Vector3(0.13f / Mathf.Abs(lossyScale5.x), 0.11f / Mathf.Abs(lossyScale5.y), 0.015f / Mathf.Abs(lossyScale5.z));
				Collider component3 = obj.GetComponent<Collider>();
				if (Object.op_Implicit((Object)(object)component3))
				{
					component3.enabled = false;
					Object.Destroy((Object)(object)component3);
				}
				if (!Object.op_Implicit((Object)(object)backboardMaterial))
				{
					Shader val4 = Shader.Find("Universal Render Pipeline/Unlit");
					if (!Object.op_Implicit((Object)(object)val4))
					{
						val4 = Shader.Find("Unlit/Color");
					}
					if (!Object.op_Implicit((Object)(object)val4))
					{
						throw new InvalidOperationException("\ud83d\udc31 Solid-color backboard shader unavailable.");
					}
					backboardMaterial = new Material(val4);
					((Object)backboardMaterial).name = "FriendBPSort.SolidBrown";
					Color val5 = default(Color);
					((Color)(ref val5))..ctor(0.32f, 0.16f, 0.07f, 1f);
					if (backboardMaterial.HasProperty("_BaseColor"))
					{
						backboardMaterial.SetColor("_BaseColor", val5);
					}
					if (backboardMaterial.HasProperty("_Color"))
					{
						backboardMaterial.SetColor("_Color", val5);
					}
				}
				obj.GetComponent<Renderer>().sharedMaterial = backboardMaterial;
				obj.SetActive(true);
				component.onPressed.AddListener(UnityAction.op_Implicit((Action)delegate
				{
					Choose(choice);
				}));
				((Behaviour)component).enabled = true;
				val.SetActive(true);
				return new SideButton
				{
					Object = val,
					Label = component2,
					Mode = choice
				};
			}
			catch
			{
				val.SetActive(false);
				Object.Destroy((Object)(object)val);
				throw;
			}
		}

		public override void OnDeinitializeMelon()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			stopped = true;
			if (historyDirty)
			{
				Save();
			}
			((MelonBase)this).HarmonyInstance.UnpatchSelf();
			Enumerator<int, List<SideButton>> enumerator = controls.Values.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					Enumerator<SideButton> enumerator2 = enumerator.Current.GetEnumerator();
					try
					{
						while (enumerator2.MoveNext())
						{
							SideButton current = enumerator2.Current;
							if (Object.op_Implicit((Object)(object)current.Object))
							{
								Object.Destroy((Object)(object)current.Object);
							}
						}
					}
					finally
					{
						((System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
					}
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			controls.Clear();
			if (Object.op_Implicit((Object)(object)staging))
			{
				Object.Destroy((Object)(object)staging);
			}
			if (Object.op_Implicit((Object)(object)backboardMaterial))
			{
				Object.Destroy((Object)(object)backboardMaterial);
			}
			FriendList[] array = Enumerable.ToArray<FriendList>((System.Collections.Generic.IEnumerable<FriendList>)lists.Values);
			foreach (FriendList val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && ((Component)val).gameObject.activeInHierarchy)
				{
					((ScrollableList)val).Refresh();
				}
			}
		}
	}
	public enum SortMode
	{
		Alphabetical,
		BattlePoints,
		FriendAdded,
		RecentlyPlayed
	}
	public static class Ranking
	{
		public static string PlainName(string name)
		{
			return Regex.Replace(name ?? "", "<[^>]*>", "");
		}

		public static int Compare(SortMode mode, int bpA, string nameA, string idA, long dateA, int bpB, string nameB, string idB, long dateB)
		{
			int num;
			switch (mode)
			{
			default:
				num = 0;
				break;
			case SortMode.FriendAdded:
			case SortMode.RecentlyPlayed:
				num = dateB.CompareTo(dateA);
				break;
			case SortMode.BattlePoints:
				num = Math.Max(-1, bpB).CompareTo(Math.Max(-1, bpA));
				break;
			}
			int num2 = num;
			if (num2 != 0)
			{
				return num2;
			}
			num2 = StringComparer.OrdinalIgnoreCase.Compare(PlainName(nameA), PlainName(nameB));
			if (num2 == 0)
			{
				return StringComparer.Ordinal.Compare(idA ?? "", idB ?? "");
			}
			return num2;
		}
	}
	public sealed class SortHistory
	{
		[field: CompilerGenerated]
		public HashSet<string> KnownFriends
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new HashSet<string>();

		[field: CompilerGenerated]
		public Dictionary<string, long> Added
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new Dictionary<string, long>();

		[field: CompilerGenerated]
		public Dictionary<string, long> Played
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new Dictionary<string, long>();

		[field: CompilerGenerated]
		public bool HasBaseline
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		public bool ObserveFriends(System.Collections.Generic.IEnumerable<string> ids, long now)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> val = new HashSet<string>(Enumerable.Where<string>(ids, (Func<string, bool>)((string id) => !string.IsNullOrEmpty(id))));
			if (val.Count == 0)
			{
				return false;
			}
			if (!HasBaseline)
			{
				KnownFriends = val;
				HasBaseline = true;
				return true;
			}
			bool result = false;
			Enumerator<string> enumerator = val.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					string current = enumerator.Current;
					if (KnownFriends.Add(current))
					{
						Added[current] = now;
						result = true;
					}
				}
				return result;
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
		}

		public void RecordPlayed(string id, long now)
		{
			if (!string.IsNullOrEmpty(id))
			{
				Played[id] = now;
			}
		}

		public long Date(SortMode mode, string master, string title)
		{
			Dictionary<string, long> val = ((mode == SortMode.FriendAdded) ? Added : Played);
			long num = 0L;
			long num2 = 0L;
			if (master != null)
			{
				val.TryGetValue(master, ref num);
			}
			if (title != null)
			{
				val.TryGetValue(title, ref num2);
			}
			return Math.Max(num, num2);
		}
	}
}