Decompiled source of ServerFavorites v1.1.7

BepInEx\plugins\WhozScott-ServerFavorites\ServerFavorites.dll

Decompiled 4 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PurrLobby;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ServerFavorites")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.7.0")]
[assembly: AssemblyInformationalVersion("1.1.7")]
[assembly: AssemblyProduct("ServerFavorites")]
[assembly: AssemblyTitle("ServerFavorites")]
[assembly: AssemblyVersion("1.1.7.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ServerFavorites
{
	[BepInPlugin("com.ontogether.serverfavorites", "ServerFavorites", "1.1.7")]
	public class ServerFavoritesPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.ontogether.serverfavorites";

		public const string PluginName = "ServerFavorites";

		public const string PluginVersion = "1.1.7";

		internal static ServerFavoritesPlugin Instance;

		internal static ManualLogSource Log;

		internal static FavoriteStore Store;

		internal static FavoritesTabController TabController;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Store = new FavoriteStore();
			TabController = new FavoritesTabController();
			_harmony = new Harmony("com.ontogether.serverfavorites");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} v{1} loaded ({2} saved host(s), Harmony patched)", "ServerFavorites", "1.1.7", Store.Count));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal sealed class FavoriteStore
	{
		private readonly string _filePath;

		private readonly Dictionary<string, FavoriteHost> _hosts = new Dictionary<string, FavoriteHost>();

		public int Count => _hosts.Count;

		public IEnumerable<FavoriteHost> All => _hosts.Values.OrderBy<FavoriteHost, string>((FavoriteHost h) => h.Label, StringComparer.OrdinalIgnoreCase);

		public FavoriteStore()
		{
			_filePath = Path.Combine(Paths.ConfigPath, "com.ontogether.serverfavorites.txt");
			Load();
		}

		public bool Contains(string steamId)
		{
			if (!string.IsNullOrEmpty(steamId))
			{
				return _hosts.ContainsKey(steamId.Trim());
			}
			return false;
		}

		public void Toggle(string steamId, string label)
		{
			string text = steamId.Trim();
			if (_hosts.ContainsKey(text))
			{
				_hosts.Remove(text);
			}
			else
			{
				_hosts[text] = new FavoriteHost
				{
					SteamId = text,
					Label = (string.IsNullOrWhiteSpace(label) ? text : label.Trim())
				};
			}
			Save();
		}

		private void Load()
		{
			_hosts.Clear();
			if (!File.Exists(_filePath))
			{
				return;
			}
			string[] array = File.ReadAllLines(_filePath);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length != 0 && !text.StartsWith("#", StringComparison.Ordinal))
				{
					int num = text.IndexOf('|');
					string text2;
					string label;
					if (num >= 0)
					{
						text2 = text.Substring(0, num).Trim();
						label = text.Substring(num + 1).Trim();
					}
					else
					{
						text2 = text;
						label = text;
					}
					if (ulong.TryParse(text2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var _))
					{
						_hosts[text2] = new FavoriteHost
						{
							SteamId = text2,
							Label = label
						};
					}
				}
			}
		}

		private void Save()
		{
			Directory.CreateDirectory(Path.GetDirectoryName(_filePath));
			IEnumerable<string> contents = from h in _hosts.Values.OrderBy<FavoriteHost, string>((FavoriteHost h) => h.Label, StringComparer.OrdinalIgnoreCase)
				select h.SteamId + "|" + h.Label;
			File.WriteAllLines(_filePath, contents, Encoding.UTF8);
		}
	}
	internal sealed class FavoriteHost
	{
		public string SteamId;

		public string Label;
	}
	internal static class LobbyHostUtility
	{
		private const uint OnTogetherAppId = 3707400u;

		public static bool TryGetHostSteamId(string lobbyId, out string hostSteamId)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			hostSteamId = null;
			if (!ulong.TryParse(lobbyId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return false;
			}
			CSteamID val = default(CSteamID);
			((CSteamID)(ref val))..ctor(result);
			string lobbyData = SteamMatchmaking.GetLobbyData(val, "owner");
			if (!string.IsNullOrEmpty(lobbyData) && ulong.TryParse(lobbyData, NumberStyles.Integer, CultureInfo.InvariantCulture, out var _))
			{
				hostSteamId = lobbyData;
				return true;
			}
			CSteamID lobbyOwner = SteamMatchmaking.GetLobbyOwner(val);
			if (((CSteamID)(ref lobbyOwner)).IsValid())
			{
				hostSteamId = lobbyOwner.m_SteamID.ToString(CultureInfo.InvariantCulture);
				return true;
			}
			return false;
		}

		public static string ResolveLabel(string hostSteamId, string fallbackName)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrWhiteSpace(fallbackName))
			{
				return fallbackName.Trim();
			}
			if (SteamManager.Initialized && ulong.TryParse(hostSteamId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				string friendPersonaName = SteamFriends.GetFriendPersonaName(new CSteamID(result));
				if (!string.IsNullOrWhiteSpace(friendPersonaName))
				{
					return friendPersonaName;
				}
			}
			return hostSteamId;
		}

		public static bool TryFindViaFriends(string hostSteamId, out Lobby lobby)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			lobby = default(Lobby);
			if (!ulong.TryParse(hostSteamId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return false;
			}
			return TryFindViaFriends(result, out lobby);
		}

		public static Task<List<Lobby>> SearchPublicLobbiesAsync(int distance)
		{
			MultiplayerManager i = MonoSingleton<MultiplayerManager>.I;
			if ((Object)(object)i == (Object)null || (Object)(object)i._lobbyManager == (Object)null || i._lobbyManager.CurrentProvider == null)
			{
				return Task.FromResult<List<Lobby>>(null);
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				{ "public", "t" },
				{
					"version",
					ConstData.Version.ToLower()
				}
			};
			return i._lobbyManager.CurrentProvider.SearchLobbiesAsync(distance, 50, dictionary);
		}

		private unsafe static bool TryFindViaFriends(ulong hostNumeric, out Lobby lobby)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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)
			//IL_0023: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			lobby = default(Lobby);
			if (!SteamManager.Initialized)
			{
				return false;
			}
			int friendCount = SteamFriends.GetFriendCount((EFriendFlags)4);
			FriendGameInfo_t val = default(FriendGameInfo_t);
			for (int i = 0; i < friendCount; i++)
			{
				CSteamID friendByIndex = SteamFriends.GetFriendByIndex(i, (EFriendFlags)4);
				if (friendByIndex.m_SteamID == hostNumeric)
				{
					if (!SteamFriends.GetFriendGamePlayed(friendByIndex, ref val))
					{
						return false;
					}
					if (((object)(*(CGameID*)(&val.m_gameID))/*cast due to .constrained prefix*/).ToString() != 3707400u.ToString(CultureInfo.InvariantCulture) || val.m_steamIDLobby == CSteamID.Nil)
					{
						return false;
					}
					return TryBuildLobby(val.m_steamIDLobby, out lobby);
				}
			}
			return false;
		}

		private static bool TryBuildLobby(CSteamID steamLobby, out Lobby lobby)
		{
			//IL_0001: 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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_0075: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			lobby = default(Lobby);
			if (steamLobby == CSteamID.Nil)
			{
				return false;
			}
			SteamMatchmaking.RequestLobbyData(steamLobby);
			int num = SteamMatchmaking.GetLobbyMemberLimit(steamLobby);
			int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(steamLobby);
			if (num <= 0)
			{
				num = numLobbyMembers + 1;
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			int lobbyDataCount = SteamMatchmaking.GetLobbyDataCount(steamLobby);
			string key = default(string);
			string value = default(string);
			for (int i = 0; i < lobbyDataCount; i++)
			{
				if (SteamMatchmaking.GetLobbyDataByIndex(steamLobby, i, ref key, 256, ref value, 256))
				{
					dictionary[key] = value;
				}
			}
			lobby = new Lobby
			{
				Name = SteamMatchmaking.GetLobbyData(steamLobby, "Name"),
				IsValid = true,
				lobbyId = steamLobby.m_SteamID.ToString(CultureInfo.InvariantCulture),
				MaxPlayers = num,
				Properties = dictionary,
				Members = new List<LobbyUser>()
			};
			return true;
		}
	}
	internal sealed class FavoritesTabController
	{
		private const float ActiveTabHeight = 106.5f;

		private const float InactiveTabHeight = 81.4f;

		private MainMenuUIController _menu;

		private RectTransform _buttonJoinAll;

		private RectTransform _buttonJoinFriends;

		private RectTransform _buttonJoinFavorites;

		private GameObject _panelJoinAll;

		private GameObject _panelJoinFriends;

		private GameObject _panelJoinFavorites;

		private Transform _contentFavorites;

		private Color _activeColor;

		private Color _inactiveColor;

		private readonly List<GameObject> _favoriteRows = new List<GameObject>();

		private bool _initialized;

		private bool _refreshRunning;

		private int _refreshToken;

		public bool IsFavoritesActive { get; private set; }

		public void EnsureInitialized(MainMenuUIController menu)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (_initialized || (Object)(object)menu == (Object)null)
			{
				return;
			}
			try
			{
				_menu = menu;
				_buttonJoinAll = GetField<RectTransform>(menu, "_buttonJoinAll");
				_buttonJoinFriends = GetField<RectTransform>(menu, "_buttonJoinFriends");
				_panelJoinAll = GetField<GameObject>(menu, "_panelJoinAll");
				_panelJoinFriends = GetField<GameObject>(menu, "_panelJoinFriends");
				_activeColor = GetField<Color>(menu, "_buttonActiveColor");
				_inactiveColor = GetField<Color>(menu, "_buttonDeactiveColor");
				if ((Object)(object)_buttonJoinAll == (Object)null || (Object)(object)_buttonJoinFriends == (Object)null || (Object)(object)_panelJoinAll == (Object)null || (Object)(object)_panelJoinFriends == (Object)null)
				{
					ServerFavoritesPlugin.Log.LogWarning((object)"Favorites tab init failed: missing join tab objects.");
					return;
				}
				CreateTabButton();
				CreatePanel(menu);
				_initialized = true;
				ServerFavoritesPlugin.Log.LogInfo((object)"ServerFavorites Favorites tab created.");
			}
			catch (Exception ex)
			{
				ServerFavoritesPlugin.Log.LogError((object)("Favorites tab init error: " + ex));
			}
		}

		private void CreateTabButton()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			_buttonJoinFavorites = Object.Instantiate<RectTransform>(_buttonJoinAll, ((Transform)_buttonJoinAll).parent);
			((Object)_buttonJoinFavorites).name = "ButtonJoinFavorites";
			Rect rect = _buttonJoinAll.rect;
			float num = ((Rect)(ref rect)).width + 14f;
			Vector2 anchoredPosition = _buttonJoinAll.anchoredPosition;
			_buttonJoinFavorites.anchoredPosition = anchoredPosition;
			_buttonJoinAll.anchoredPosition = anchoredPosition + new Vector2(0f - num, 0f);
			_buttonJoinFavorites.sizeDelta = new Vector2(_buttonJoinAll.sizeDelta.x, 81.4f);
			SendTabToBack(_buttonJoinFavorites);
			StripLocalizers(((Component)_buttonJoinFavorites).gameObject);
			SetButtonLabel(_buttonJoinFavorites, "Favorites");
			StyleTab(_buttonJoinFavorites, active: false);
			Button component = ((Component)_buttonJoinFavorites).GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				component.onClick = new ButtonClickedEvent();
				((UnityEvent)component.onClick).AddListener(new UnityAction(ShowFavoritesTab));
			}
		}

		private void CreatePanel(MainMenuUIController menu)
		{
			_panelJoinFavorites = Object.Instantiate<GameObject>(_panelJoinFriends, _panelJoinFriends.transform.parent);
			((Object)_panelJoinFavorites).name = "PanelJoinFavorites";
			string name = ((Object)menu.SessionListContentFriendsParent).name;
			_contentFavorites = FindInChildrenByName(_panelJoinFavorites.transform, name) ?? _panelJoinFavorites.transform;
			for (int num = _contentFavorites.childCount - 1; num >= 0; num--)
			{
				Transform child = _contentFavorites.GetChild(num);
				if ((Object)(object)((Component)child).GetComponent<LobbyItemController>() != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)child).gameObject);
				}
			}
			_panelJoinFavorites.SetActive(false);
		}

		public void OnLeaveFavorites()
		{
			if (_initialized && IsFavoritesActive)
			{
				IsFavoritesActive = false;
				if ((Object)(object)_panelJoinFavorites != (Object)null)
				{
					_panelJoinFavorites.SetActive(false);
				}
				StyleTab(_buttonJoinFavorites, active: false);
				SetTabHeight(_buttonJoinFavorites, 81.4f);
				SendTabToBack(_buttonJoinFavorites);
				_refreshToken++;
				if (_refreshRunning && (Object)(object)_menu != (Object)null && (Object)(object)_menu.CanvasBlockerImage != (Object)null)
				{
					_menu.CanvasBlockerImage.SetActive(false);
				}
			}
		}

		public void ShowFavoritesTab()
		{
			if (_initialized)
			{
				IsFavoritesActive = true;
				_panelJoinAll.SetActive(false);
				_panelJoinFriends.SetActive(false);
				_panelJoinFavorites.SetActive(true);
				StyleTab(_buttonJoinFavorites, active: true);
				StyleTab(_buttonJoinAll, active: false);
				StyleTab(_buttonJoinFriends, active: false);
				SetTabHeight(_buttonJoinFavorites, 106.5f);
				SetTabHeight(_buttonJoinAll, 81.4f);
				SetTabHeight(_buttonJoinFriends, 81.4f);
				ApplyTabLayering(_buttonJoinFavorites);
				if (!_refreshRunning)
				{
					((MonoBehaviour)_menu).StartCoroutine(RefreshFavorites(++_refreshToken));
				}
			}
		}

		private IEnumerator RefreshFavorites(int token)
		{
			_refreshRunning = true;
			ClearRows();
			try
			{
				_menu.CanvasBlockerImage.SetActive(true);
				yield return null;
				int onlineCount = 0;
				foreach (FavoriteHost favorite in ServerFavoritesPlugin.Store.All.ToList())
				{
					if (!IsFavoritesActive || token != _refreshToken)
					{
						yield break;
					}
					bool online = false;
					Lobby lobby = default(Lobby);
					try
					{
						online = LobbyHostUtility.TryFindViaFriends(favorite.SteamId, out lobby);
					}
					catch (Exception ex)
					{
						ServerFavoritesPlugin.Log.LogWarning((object)("Favorite friend lookup failed for " + favorite.Label + ": " + ex.Message));
					}
					if (!online)
					{
						HashSet<string> seen = new HashSet<string>();
						for (int distance = 1; distance <= 3; distance++)
						{
							if (online)
							{
								break;
							}
							Task<List<Lobby>> search = null;
							try
							{
								search = LobbyHostUtility.SearchPublicLobbiesAsync(distance);
							}
							catch (Exception ex2)
							{
								ServerFavoritesPlugin.Log.LogWarning((object)("Lobby search start failed: " + ex2.Message));
							}
							if (search == null)
							{
								break;
							}
							float searchStarted = Time.realtimeSinceStartup;
							while (!search.IsCompleted && Time.realtimeSinceStartup - searchStarted < 6f)
							{
								if (!IsFavoritesActive || token != _refreshToken)
								{
									yield break;
								}
								yield return null;
							}
							if (!search.IsCompleted)
							{
								ServerFavoritesPlugin.Log.LogWarning((object)"Lobby search timed out while refreshing Favorites.");
							}
							else
							{
								if (search.Status != TaskStatus.RanToCompletion || search.Result == null)
								{
									continue;
								}
								foreach (Lobby item in search.Result)
								{
									if (item.IsValid && !string.IsNullOrEmpty(item.lobbyId) && seen.Add(item.lobbyId) && LobbyHostUtility.TryGetHostSteamId(item.lobbyId, out var hostSteamId) && hostSteamId == favorite.SteamId)
									{
										lobby = item;
										online = true;
										break;
									}
								}
							}
						}
					}
					if (online)
					{
						onlineCount++;
						GameObject val = Object.Instantiate<GameObject>(_menu.SessionListItemPrefab, _contentFavorites);
						val.GetComponent<LobbyItemController>().SetLobby(lobby, 1);
						FavoriteRowUi.AttachStar(val, favorite.SteamId, favorite.Label, starred: true);
						_favoriteRows.Add(val);
					}
					else
					{
						_favoriteRows.Add(CreateOfflineRow(favorite));
					}
					yield return null;
				}
				if (ServerFavoritesPlugin.Store.Count > 0 && onlineCount == 0)
				{
					_favoriteRows.Add(CreateMessageRow("Saved hosts are offline or not hosting right now."));
				}
			}
			finally
			{
				FavoritesTabController favoritesTabController = this;
				if (token == favoritesTabController._refreshToken && (Object)(object)favoritesTabController._menu != (Object)null && (Object)(object)favoritesTabController._menu.CanvasBlockerImage != (Object)null)
				{
					favoritesTabController._menu.CanvasBlockerImage.SetActive(false);
				}
				favoritesTabController._refreshRunning = false;
			}
		}

		private void ClearRows()
		{
			for (int num = _favoriteRows.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)_favoriteRows[num] != (Object)null)
				{
					Object.Destroy((Object)(object)_favoriteRows[num]);
				}
			}
			_favoriteRows.Clear();
		}

		private GameObject CreateOfflineRow(FavoriteHost favorite)
		{
			GameObject val = Object.Instantiate<GameObject>(_menu.SessionListItemPrefab, _contentFavorites);
			Button[] componentsInChildren = val.GetComponentsInChildren<Button>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Selectable)componentsInChildren[i]).interactable = false;
			}
			TMP_Text componentInChildren = val.GetComponentInChildren<TMP_Text>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = favorite.Label + "  (offline)";
			}
			FavoriteRowUi.AttachStar(val, favorite.SteamId, favorite.Label, starred: true);
			return val;
		}

		private GameObject CreateMessageRow(string message)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			GameObject val = new GameObject("FavoriteInfoRow", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(_contentFavorites, false);
			LayoutElement obj = val.AddComponent<LayoutElement>();
			obj.minHeight = 48f;
			obj.preferredHeight = 48f;
			obj.minWidth = 400f;
			Text obj2 = val.AddComponent<Text>();
			obj2.font = FavoriteRowUi.GetFont();
			obj2.text = message;
			((Graphic)obj2).color = new Color(0.32f, 0.27f, 0.22f);
			obj2.alignment = (TextAnchor)3;
			obj2.fontSize = 20;
			obj2.horizontalOverflow = (HorizontalWrapMode)1;
			obj2.verticalOverflow = (VerticalWrapMode)1;
			val.GetComponent<RectTransform>().sizeDelta = new Vector2(700f, 48f);
			return val;
		}

		private void StyleTab(RectTransform button, bool active)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)button == (Object)null))
			{
				Image component = ((Component)button).GetComponent<Image>();
				if ((Object)(object)component != (Object)null)
				{
					((Graphic)component).color = (active ? _activeColor : _inactiveColor);
				}
			}
		}

		private static void SetTabHeight(RectTransform button, float height)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)button != (Object)null)
			{
				button.sizeDelta = new Vector2(button.sizeDelta.x, height);
			}
		}

		private void SendTabToBack(RectTransform tab)
		{
			if (!((Object)(object)tab == (Object)null))
			{
				int num = ((Transform)tab).GetSiblingIndex();
				if ((Object)(object)_buttonJoinAll != (Object)null)
				{
					num = Mathf.Min(num, ((Transform)_buttonJoinAll).GetSiblingIndex());
				}
				if ((Object)(object)_buttonJoinFriends != (Object)null)
				{
					num = Mathf.Min(num, ((Transform)_buttonJoinFriends).GetSiblingIndex());
				}
				((Transform)tab).SetSiblingIndex(num);
			}
		}

		private void ApplyTabLayering(RectTransform active)
		{
			SendTabToBack(_buttonJoinFavorites);
			SendTabToBack(_buttonJoinAll);
			SendTabToBack(_buttonJoinFriends);
			if ((Object)(object)active != (Object)null)
			{
				((Transform)active).SetAsLastSibling();
			}
		}

		public void ReassertNativeTabLayering()
		{
			if (!_initialized)
			{
				return;
			}
			try
			{
				bool flag = (bool)AccessTools.Field(typeof(MainMenuUIController), "_isJoinAllPanel").GetValue(_menu);
				ApplyTabLayering(flag ? _buttonJoinAll : _buttonJoinFriends);
			}
			catch (Exception ex)
			{
				ServerFavoritesPlugin.Log.LogWarning((object)("Tab layering reassert failed: " + ex.Message));
			}
		}

		private static void SetButtonLabel(RectTransform button, string label)
		{
			bool flag = false;
			TMP_Text[] componentsInChildren = ((Component)button).GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].text = label;
				flag = true;
			}
			if (!flag)
			{
				Text componentInChildren = ((Component)button).GetComponentInChildren<Text>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.text = label;
				}
			}
		}

		private static void StripLocalizers(GameObject root)
		{
			Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && (((object)val).GetType().FullName ?? string.Empty).IndexOf("Localiz", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}

		private static Transform FindInChildrenByName(Transform root, string name)
		{
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}

		private static T GetField<T>(object instance, string field)
		{
			object obj = AccessTools.Field(instance.GetType(), field)?.GetValue(instance);
			if (obj is T)
			{
				return (T)obj;
			}
			return default(T);
		}
	}
	internal static class FavoriteRowUi
	{
		private static Sprite _starSprite;

		public static Font GetFont()
		{
			return Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf") ?? Resources.GetBuiltinResource<Font>("Arial.ttf");
		}

		private static void ShiftNameText(GameObject row, float dx)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				LobbyItemController component = row.GetComponent<LobbyItemController>();
				if (!((Object)(object)component == (Object)null))
				{
					object? obj = AccessTools.Field(typeof(LobbyItemController), "_sessionNameText")?.GetValue(component);
					TMP_Text val = (TMP_Text)((obj is TMP_Text) ? obj : null);
					if (!((Object)(object)val == (Object)null))
					{
						RectTransform rectTransform = val.rectTransform;
						rectTransform.offsetMin = new Vector2(rectTransform.offsetMin.x + dx, rectTransform.offsetMin.y);
					}
				}
			}
			catch (Exception ex)
			{
				ServerFavoritesPlugin.Log.LogWarning((object)("Could not shift session name: " + ex.Message));
			}
		}

		public static void AttachStar(GameObject row, string hostSteamId, string label, bool starred)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: 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_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Expected O, but got Unknown
			if ((Object)(object)row == (Object)null || string.IsNullOrEmpty(hostSteamId))
			{
				return;
			}
			Transform val = row.transform.Find("FavoriteStarButton");
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
			GameObject val2 = new GameObject("FavoriteStarButton", new Type[4]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(Button)
			});
			val2.transform.SetParent(row.transform, false);
			val2.transform.SetAsLastSibling();
			RectTransform component = val2.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 0.5f);
			component.anchorMax = new Vector2(0f, 0.5f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.anchoredPosition = new Vector2(31f, 0f);
			component.sizeDelta = new Vector2(42f, 42f);
			Image component2 = val2.GetComponent<Image>();
			((Graphic)component2).color = new Color(1f, 1f, 1f, 0f);
			((Graphic)component2).raycastTarget = true;
			((Graphic)CreateStarLayer(val2.transform, "StarOutline", 34f)).color = Color.black;
			Image fillImage = CreateStarLayer(val2.transform, "StarFill", 25f);
			ApplyStarVisual(fillImage, starred);
			Button component3 = val2.GetComponent<Button>();
			string capturedHost = hostSteamId;
			string capturedLabel = label;
			((UnityEvent)component3.onClick).AddListener((UnityAction)delegate
			{
				ServerFavoritesPlugin.Store.Toggle(capturedHost, capturedLabel);
				bool flag = ServerFavoritesPlugin.Store.Contains(capturedHost);
				ApplyStarVisual(fillImage, flag);
				ServerFavoritesPlugin.Log.LogInfo((object)(flag ? ("Saved favorite host " + capturedLabel + " (" + capturedHost + ")") : ("Removed favorite host " + capturedLabel + " (" + capturedHost + ")")));
				if (ServerFavoritesPlugin.TabController != null && ServerFavoritesPlugin.TabController.IsFavoritesActive)
				{
					ServerFavoritesPlugin.TabController.ShowFavoritesTab();
				}
			});
		}

		private static void ApplyStarVisual(Image starImage, bool starred)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			((Graphic)starImage).color = (starred ? new Color(1f, 0.76f, 0.05f) : new Color(0.97f, 0.91f, 0.8f));
		}

		private static Image CreateStarLayer(Transform parent, string name, float size)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0.5f);
			component.anchorMax = new Vector2(0.5f, 0.5f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.anchoredPosition = Vector2.zero;
			component.sizeDelta = new Vector2(size, size);
			Image component2 = val.GetComponent<Image>();
			component2.sprite = GetStarSprite();
			component2.type = (Type)0;
			component2.preserveAspect = true;
			((Graphic)component2).raycastTarget = false;
			return component2;
		}

		private static Sprite GetStarSprite()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: 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_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_starSprite != (Object)null)
			{
				return _starSprite;
			}
			Texture2D val = new Texture2D(96, 96, (TextureFormat)5, false);
			((Texture)val).filterMode = (FilterMode)1;
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(1f, 1f, 1f, 0f);
			Color white = Color.white;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(47.5f, 47.5f);
			Vector2[] array = (Vector2[])(object)new Vector2[10];
			for (int i = 0; i < array.Length; i++)
			{
				float num = ((i % 2 == 0) ? 42f : 18f);
				float num2 = MathF.PI / 180f * (-90f + (float)i * 36f);
				array[i] = val3 + new Vector2(Mathf.Cos(num2), Mathf.Sin(num2)) * num;
			}
			Vector2 point = default(Vector2);
			for (int j = 0; j < 96; j++)
			{
				for (int k = 0; k < 96; k++)
				{
					int num3 = 0;
					for (int l = 0; l < 4; l++)
					{
						for (int m = 0; m < 4; m++)
						{
							((Vector2)(ref point))..ctor((float)k + ((float)m + 0.5f) / 4f, (float)j + ((float)l + 0.5f) / 4f);
							if (IsInsidePolygon(array, point))
							{
								num3++;
							}
						}
					}
					if (num3 == 0)
					{
						val.SetPixel(k, j, val2);
						continue;
					}
					float num4 = (float)num3 / 16f;
					val.SetPixel(k, j, new Color(white.r, white.g, white.b, num4));
				}
			}
			val.Apply(false, true);
			_starSprite = Sprite.Create(val, new Rect(0f, 0f, 96f, 96f), new Vector2(0.5f, 0.5f), 100f);
			return _starSprite;
		}

		private static bool IsInsidePolygon(Vector2[] polygon, Vector2 point)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			int num = polygon.Length - 1;
			for (int i = 0; i < polygon.Length; i++)
			{
				if (polygon[i].y > point.y != polygon[num].y > point.y && point.x < (polygon[num].x - polygon[i].x) * (point.y - polygon[i].y) / (polygon[num].y - polygon[i].y) + polygon[i].x)
				{
					flag = !flag;
				}
				num = i;
			}
			return flag;
		}
	}
	[HarmonyPatch(typeof(MainMenuUIController), "Start")]
	internal static class MainMenuUIControllerStartPatch
	{
		private static void Postfix(MainMenuUIController __instance)
		{
			ServerFavoritesPlugin.TabController.EnsureInitialized(__instance);
		}
	}
	[HarmonyPatch(typeof(MainMenuUIController), "ButtonPlay")]
	internal static class MainMenuUIControllerPlayPatch
	{
		private static void Postfix(MainMenuUIController __instance)
		{
			ServerFavoritesPlugin.TabController.EnsureInitialized(__instance);
		}
	}
	[HarmonyPatch(typeof(MainMenuUIController), "ButtonPanelJoin")]
	internal static class MainMenuUIControllerAllTabPatch
	{
		private static void Prefix(MainMenuUIController __instance)
		{
			if (ServerFavoritesPlugin.TabController.IsFavoritesActive)
			{
				AccessTools.Field(typeof(MainMenuUIController), "_isJoinAllPanel").SetValue(__instance, false);
				ServerFavoritesPlugin.TabController.OnLeaveFavorites();
			}
		}

		private static void Postfix()
		{
			ServerFavoritesPlugin.TabController.ReassertNativeTabLayering();
		}
	}
	[HarmonyPatch(typeof(MainMenuUIController), "ButtonPanelJoinFriends")]
	internal static class MainMenuUIControllerFriendsTabPatch
	{
		private static void Prefix(MainMenuUIController __instance)
		{
			if (ServerFavoritesPlugin.TabController.IsFavoritesActive)
			{
				AccessTools.Field(typeof(MainMenuUIController), "_isJoinAllPanel").SetValue(__instance, true);
				ServerFavoritesPlugin.TabController.OnLeaveFavorites();
			}
		}

		private static void Postfix()
		{
			ServerFavoritesPlugin.TabController.ReassertNativeTabLayering();
		}
	}
	[HarmonyPatch(typeof(LobbyItemController), "SetLobby")]
	internal static class LobbyItemControllerSetLobbyPatch
	{
		private static void Postfix(LobbyItemController __instance, Lobby lobbyInfo)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)__instance == (Object)null) && lobbyInfo.IsValid && !string.IsNullOrEmpty(lobbyInfo.lobbyId) && LobbyHostUtility.TryGetHostSteamId(lobbyInfo.lobbyId, out var hostSteamId))
				{
					string label = LobbyHostUtility.ResolveLabel(hostSteamId, lobbyInfo.Name);
					FavoriteRowUi.AttachStar(((Component)__instance).gameObject, hostSteamId, label, ServerFavoritesPlugin.Store.Contains(hostSteamId));
				}
			}
			catch (Exception ex)
			{
				ServerFavoritesPlugin.Log.LogWarning((object)("Skipped favorite star on lobby row: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(LobbyItemController), "SetFriendLobby")]
	internal static class LobbyItemControllerSetFriendLobbyPatch
	{
		private static void Postfix(LobbyItemController __instance, Lobby lobbyInfo)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)__instance == (Object)null) && lobbyInfo.IsValid && !string.IsNullOrEmpty(lobbyInfo.lobbyId) && LobbyHostUtility.TryGetHostSteamId(lobbyInfo.lobbyId, out var hostSteamId))
				{
					string label = LobbyHostUtility.ResolveLabel(hostSteamId, lobbyInfo.Name);
					FavoriteRowUi.AttachStar(((Component)__instance).gameObject, hostSteamId, label, ServerFavoritesPlugin.Store.Contains(hostSteamId));
				}
			}
			catch (Exception ex)
			{
				ServerFavoritesPlugin.Log.LogWarning((object)("Skipped favorite star on friend lobby row: " + ex.Message));
			}
		}
	}
}