Decompiled source of LobbyRework v1.5.32

BepInEx/plugins/LobbyRework/LobbyRework.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using Steamworks.Data;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
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("LobbyRework")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.3.0")]
[assembly: AssemblyInformationalVersion("1.5.3")]
[assembly: AssemblyProduct("LobbyRework")]
[assembly: AssemblyTitle("LobbyRework")]
[assembly: AssemblyVersion("1.5.3.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 LobbyRework
{
	[BepInPlugin("LobbyRework.1.5.3", "Lobby Rework", "1.5.3")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Action<ScriptableRenderContext, Camera> <0>__OnBeginCameraRendering;

			public static CameraCallback <1>__OnCameraPreCull;

			public static Action <2>__OnApplicationQuitting;
		}

		public const string PluginGuid = "LobbyRework.1.5.3";

		private const string HarmonyId = "lobbyrework";

		public const string PluginName = "Lobby Rework";

		public const string PluginVersion = "1.5.3";

		internal static ManualLogSource ModLog;

		internal static ConfigEntry<float> PollInterval;

		internal static ConfigEntry<float> InvalidRemoveDelay;

		internal static ConfigEntry<float> LobbyScrollStep;

		internal static ConfigEntry<bool> FriendLobbies;

		internal static ConfigEntry<bool> BlockedLobbies;

		internal static ConfigEntry<bool> ShowHostName;

		internal static ConfigEntry<bool> ShowLobbyInfo;

		internal static ConfigEntry<string> SearchTags;

		internal static ConfigEntry<bool> MinimizeProbeExposure;

		internal static ConfigEntry<bool> Logging;

		private static Harmony harmony;

		private static bool callbacksRegistered;

		private static int lastProcessedFrame = -1;

		internal static bool LoggingEnabled
		{
			get
			{
				if (Logging != null)
				{
					return Logging.Value;
				}
				return false;
			}
		}

		internal static bool MinimizeProbeExposureEnabled
		{
			get
			{
				if (MinimizeProbeExposure != null)
				{
					return MinimizeProbeExposure.Value;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			ModLog = ((BaseUnityPlugin)this).Logger;
			DeleteObsoleteLobbyReworkConfigs();
			BindConfig();
			StableLobbyManager.ClearLocalProbePresence();
			LogInfo("Lobby Rework 1.5.3 loaded.");
			harmony = new Harmony("lobbyrework");
			harmony.PatchAll();
			RegisterStaticCallbacks();
			LogInfo("Stable lobby cache enabled; automatic refreshes no longer rebuild the whole list.");
		}

		private void DeleteObsoleteLobbyReworkConfigs()
		{
			try
			{
				string fullPath = Path.GetFullPath(((BaseUnityPlugin)this).Config.ConfigFilePath);
				string[] files = Directory.GetFiles(Paths.ConfigPath, "*.cfg", SearchOption.TopDirectoryOnly);
				foreach (string path in files)
				{
					if (!string.Equals(Path.GetFullPath(path), fullPath, StringComparison.OrdinalIgnoreCase))
					{
						string fileName = Path.GetFileName(path);
						if (!fileName.StartsWith("LobbyFilter", StringComparison.OrdinalIgnoreCase) && !string.Equals(fileName, "lobbyfilter.cfg", StringComparison.OrdinalIgnoreCase) && IsObsoleteLobbyReworkConfigName(fileName))
						{
							File.Delete(path);
							LogInfo("Deleted obsolete Lobby Rework config '" + fileName + "'.");
						}
					}
				}
			}
			catch (Exception ex)
			{
				LogWarning("Could not clean up obsolete Lobby Rework config files: " + ex.Message);
			}
		}

		private static bool IsObsoleteLobbyReworkConfigName(string fileName)
		{
			if (string.IsNullOrEmpty(fileName))
			{
				return false;
			}
			if (!string.Equals(fileName, "LobbyRework.cfg", StringComparison.OrdinalIgnoreCase) && !fileName.StartsWith("LobbyRework.", StringComparison.OrdinalIgnoreCase) && !fileName.StartsWith("LobbyRework_", StringComparison.OrdinalIgnoreCase))
			{
				return fileName.StartsWith("LobbyRework-", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		private void BindConfig()
		{
			PollInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "PollInterval", 0.125f, "Seconds between lobby checks");
			InvalidRemoveDelay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "InvalidRemoveDelay", 30f, "Seconds a lobby must remain continuously unjoinable before its removed");
			LobbyScrollStep = ((BaseUnityPlugin)this).Config.Bind<float>("General", "LobbyScrollStep", 32f, "Pixels the lobby list moves for each mouse-wheel event");
			FriendLobbies = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "FriendLobbies", true, "Highlight lobbies containing Steam friends in green");
			BlockedLobbies = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BlockedLobbies", false, "Mark lobbies hosted by blocked Steam users red and disable Join. Blocked-host lobbies are never automatically removed while this is enabled");
			ShowHostName = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowHostName", true, "Show the Steam host name at the bottom center of every lobby row");
			ShowLobbyInfo = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowLobbyInfo", true, "Show the circled info button on lobby showing the member list");
			SearchTags = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Search tags", "", "Lobby name tags to hide when Hide tags is enabled");
			SearchTags.SettingChanged += delegate
			{
				StableLobbyManager.NotifySearchTagsChanged();
			};
			MinimizeProbeExposure = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "MinimizeProbeExposure", false, "Probe each lobby at most once instead of twice, and skip re-probing on hover. Reduces how often your Steam identity briefly appears in lobbies hosted by players who don't have this mod, at the cost of slightly staler host name/friend/blocked info.");
			Logging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Logging", false, "Enable Lobby Rework informational logging. Warnings are still logged when this is false.");
			((BaseUnityPlugin)this).Config.Save();
			LogInfo($"Config loaded: PollInterval={PollInterval.Value:0.###}s, " + $"InvalidRemoveDelay={InvalidRemoveDelay.Value:0.###}s, " + $"LobbyScrollStep={LobbyScrollStep.Value:0.###}px, " + $"FriendLobbies={FriendLobbies.Value}, " + $"BlockedLobbies={BlockedLobbies.Value}, " + $"ShowHostName={ShowHostName.Value}, " + $"ShowLobbyInfo={ShowLobbyInfo.Value}, " + "SearchTags='" + SearchTags.Value + "', " + $"MinimizeProbeExposure={MinimizeProbeExposure.Value}.");
		}

		private static void RegisterStaticCallbacks()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_0043: 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_004e: Expected O, but got Unknown
			if (!callbacksRegistered)
			{
				callbacksRegistered = true;
				RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
				CameraCallback onPreCull = Camera.onPreCull;
				object obj = <>O.<1>__OnCameraPreCull;
				if (obj == null)
				{
					CameraCallback val = OnCameraPreCull;
					<>O.<1>__OnCameraPreCull = val;
					obj = (object)val;
				}
				Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)onPreCull, (Delegate?)obj);
				Application.quitting += OnApplicationQuitting;
			}
		}

		private static void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
		{
			ProcessFrame();
		}

		private static void OnCameraPreCull(Camera camera)
		{
			ProcessFrame();
		}

		private static void ProcessFrame()
		{
			int frameCount = Time.frameCount;
			if (frameCount != lastProcessedFrame)
			{
				lastProcessedFrame = frameCount;
				StableLobbyManager.Tick();
			}
		}

		private void OnDestroy()
		{
			LogInfo("Plugin OnDestroy called; stable lobby cache remains active.");
		}

		private static void OnApplicationQuitting()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			if (callbacksRegistered)
			{
				RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering;
				CameraCallback onPreCull = Camera.onPreCull;
				object obj = <>O.<1>__OnCameraPreCull;
				if (obj == null)
				{
					CameraCallback val = OnCameraPreCull;
					<>O.<1>__OnCameraPreCull = val;
					obj = (object)val;
				}
				Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)onPreCull, (Delegate?)obj);
				Application.quitting -= OnApplicationQuitting;
				callbacksRegistered = false;
			}
			StableLobbyManager.Shutdown();
		}

		internal static void LogInfo(string message)
		{
			if (LoggingEnabled)
			{
				ManualLogSource modLog = ModLog;
				if (modLog != null)
				{
					modLog.LogInfo((object)message);
				}
			}
		}

		internal static void LogWarning(string message)
		{
			ManualLogSource modLog = ModLog;
			if (modLog != null)
			{
				modLog.LogWarning((object)message);
			}
		}
	}
	internal sealed class LobbyInspectHover : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		internal ulong LobbyId;

		internal GameObject TooltipRoot;

		internal RectTransform TooltipRect;

		internal TMP_Text TooltipText;

		internal bool IsHovered;

		internal bool IsTooltipHovered;

		private float hideAtTime = -1f;

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

		public void OnPointerEnter(PointerEventData eventData)
		{
			IsHovered = true;
			hideAtTime = -1f;
			RefreshTooltip();
			if ((Object)(object)TooltipRoot != (Object)null)
			{
				TooltipRoot.SetActive(true);
				TooltipRoot.transform.SetAsLastSibling();
			}
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			IsHovered = false;
			ScheduleHide();
		}

		private void LateUpdate()
		{
			if (!((Object)(object)TooltipRoot == (Object)null) && TooltipRoot.activeSelf && !IsHovered && !IsTooltipHovered && !(hideAtTime < 0f) && !(Time.unscaledTime < hideAtTime))
			{
				TooltipRoot.SetActive(false);
				hideAtTime = -1f;
			}
		}

		internal void SetTooltipHovered(bool hovered)
		{
			IsTooltipHovered = hovered;
			if (hovered)
			{
				hideAtTime = -1f;
				if ((Object)(object)TooltipRoot != (Object)null)
				{
					TooltipRoot.SetActive(true);
					TooltipRoot.transform.SetAsLastSibling();
				}
			}
			else
			{
				ScheduleHide();
			}
		}

		private void ScheduleHide()
		{
			hideAtTime = Time.unscaledTime + 0.25f;
		}

		internal void RefreshIfVisible()
		{
			if (IsHovered || IsTooltipHovered)
			{
				RefreshTooltip();
			}
		}

		internal void RefreshTooltip()
		{
			//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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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)
			if (!((Object)(object)TooltipText == (Object)null))
			{
				TooltipText.text = StableLobbyManager.GetLobbyInspectText(LobbyId);
				TooltipText.ForceMeshUpdate(false, false);
				if ((Object)(object)TooltipRect != (Object)null)
				{
					Vector2 preferredValues = TooltipText.GetPreferredValues(TooltipText.text, 10000f, 10000f);
					Vector2 sizeDelta = TooltipRect.sizeDelta;
					sizeDelta.x = Mathf.Max(150f, preferredValues.x + 42f);
					sizeDelta.y = Mathf.Max(48f, preferredValues.y + 18f);
					TooltipRect.sizeDelta = sizeDelta;
					TooltipText.ForceMeshUpdate(false, false);
				}
				RebuildSteamProfileButtons();
			}
		}

		private void RebuildSteamProfileButtons()
		{
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Expected O, but got Unknown
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)TooltipText == (Object)null)
			{
				return;
			}
			List<KeyValuePair<ulong, string>> list = new List<KeyValuePair<ulong, string>>();
			if (!StableLobbyManager.GetLobbyInspectMembers(LobbyId, list) || list.Count == 0)
			{
				for (int i = 0; i < profileButtons.Count; i++)
				{
					GameObject val = profileButtons[i];
					if ((Object)(object)val != (Object)null)
					{
						Object.Destroy((Object)(object)val);
					}
				}
				profileButtons.Clear();
				return;
			}
			TooltipText.ForceMeshUpdate(false, false);
			TMP_TextInfo textInfo = TooltipText.textInfo;
			if (textInfo == null || textInfo.lineInfo == null)
			{
				return;
			}
			Sprite steamProfileSprite = StableLobbyManager.GetSteamProfileSprite();
			int num = Mathf.Min(list.Count, Mathf.Max(0, textInfo.lineCount - 1));
			while (profileButtons.Count > num)
			{
				int index = profileButtons.Count - 1;
				GameObject val2 = profileButtons[index];
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)val2);
				}
				profileButtons.RemoveAt(index);
			}
			for (int j = 0; j < num; j++)
			{
				int num2 = j + 1;
				TMP_LineInfo val3 = textInfo.lineInfo[num2];
				float num3 = (val3.ascender + val3.descender) * 0.5f;
				float num4 = val3.lineExtents.max.x + 8f;
				ulong key = list[j].Key;
				GameObject val4 = ((j < profileButtons.Count) ? profileButtons[j] : null);
				LobbySteamProfileButton lobbySteamProfileButton = (((Object)(object)val4 != (Object)null) ? val4.GetComponent<LobbySteamProfileButton>() : null);
				if ((Object)(object)val4 == (Object)null || (Object)(object)lobbySteamProfileButton == (Object)null || lobbySteamProfileButton.SteamId != key)
				{
					if ((Object)(object)val4 != (Object)null)
					{
						Object.Destroy((Object)(object)val4);
					}
					val4 = new GameObject("LobbyReworkSteamProfile_" + key);
					val4.transform.SetParent((Transform)(object)TooltipText.rectTransform, false);
					Image val5 = val4.AddComponent<Image>();
					val5.sprite = steamProfileSprite;
					val5.preserveAspect = true;
					((Graphic)val5).raycastTarget = true;
					((Graphic)val5).color = Color.black;
					lobbySteamProfileButton = val4.AddComponent<LobbySteamProfileButton>();
					lobbySteamProfileButton.SteamId = key;
					lobbySteamProfileButton.Icon = val5;
					if (j < profileButtons.Count)
					{
						profileButtons[j] = val4;
					}
					else
					{
						profileButtons.Add(val4);
					}
				}
				Image val6 = lobbySteamProfileButton.Icon;
				if ((Object)(object)val6 == (Object)null)
				{
					val6 = (lobbySteamProfileButton.Icon = val4.GetComponent<Image>());
				}
				if ((Object)(object)val6 != (Object)null)
				{
					val6.sprite = steamProfileSprite;
					val6.preserveAspect = true;
					((Graphic)val6).raycastTarget = true;
					if (!lobbySteamProfileButton.IsHovered)
					{
						((Graphic)val6).color = Color.black;
					}
					RectTransform rectTransform = ((Graphic)val6).rectTransform;
					rectTransform.sizeDelta = new Vector2(12f, 12f);
					((Transform)rectTransform).localPosition = new Vector3(num4 + 6f, num3, 0f);
				}
			}
		}
	}
	internal sealed class LobbySteamProfileButton : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerClickHandler
	{
		internal ulong SteamId;

		internal Image Icon;

		internal bool IsHovered;

		public void OnPointerEnter(PointerEventData eventData)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			IsHovered = true;
			if ((Object)(object)Icon != (Object)null)
			{
				((Graphic)Icon).color = Color.white;
			}
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			IsHovered = false;
			if ((Object)(object)Icon != (Object)null)
			{
				((Graphic)Icon).color = Color.black;
			}
		}

		public void OnPointerClick(PointerEventData eventData)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			if (eventData == null || (int)eventData.button == 0)
			{
				StableLobbyManager.OpenSteamProfile(SteamId);
			}
		}
	}
	internal sealed class LobbyInspectTooltipHover : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		internal LobbyInspectHover Owner;

		public void OnPointerEnter(PointerEventData eventData)
		{
			if ((Object)(object)Owner != (Object)null)
			{
				Owner.SetTooltipHovered(hovered: true);
			}
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			if ((Object)(object)Owner != (Object)null)
			{
				Owner.SetTooltipHovered(hovered: false);
			}
		}
	}
	internal sealed class LobbyScrollWheelLimiter : MonoBehaviour, IScrollHandler, IEventSystemHandler
	{
		internal ScrollRect TargetScrollRect;

		internal RectTransform FallbackContent;

		public void OnScroll(PointerEventData eventData)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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_00ae: 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)
			if (eventData == null || (Object)(object)TargetScrollRect == (Object)null || !((Behaviour)TargetScrollRect).isActiveAndEnabled)
			{
				return;
			}
			float y = eventData.scrollDelta.y;
			if (Mathf.Approximately(y, 0f))
			{
				return;
			}
			RectTransform val = (((Object)(object)TargetScrollRect.content != (Object)null) ? TargetScrollRect.content : FallbackContent);
			RectTransform val2 = TargetScrollRect.viewport;
			if ((Object)(object)val2 == (Object)null)
			{
				Transform transform = ((Component)TargetScrollRect).transform;
				val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			}
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
			{
				Rect rect = val.rect;
				float height = ((Rect)(ref rect)).height;
				rect = val2.rect;
				float num = Mathf.Max(0f, height - ((Rect)(ref rect)).height);
				if (!(num <= 0.01f))
				{
					float num2 = Mathf.Sign(y);
					float num3 = StableLobbyManager.GetLobbyScrollStep() / num;
					TargetScrollRect.StopMovement();
					TargetScrollRect.verticalNormalizedPosition = Mathf.Clamp01(TargetScrollRect.verticalNormalizedPosition + num2 * num3);
					((AbstractEventData)eventData).Use();
				}
			}
		}
	}
	internal sealed class LobbyState
	{
		internal ulong LobbyId;

		internal Lobby Lobby;

		internal string Name;

		internal ulong HostSteamId;

		internal string HostName;

		internal bool HostIsFriend;

		internal bool HostIsBlocked;

		internal bool HostConfirmedByProbe;

		internal readonly Dictionary<ulong, string> FriendsInLobby = new Dictionary<ulong, string>();

		internal readonly Dictionary<ulong, string> MembersInLobby = new Dictionary<ulong, string>();

		internal bool MembersKnown;

		internal bool Invalid;

		internal string Reason;

		internal bool ProbeJoinRejected;

		internal string ProbeJoinRejectReason;

		internal float LastProbeTime = -1f;

		internal float FirstDetectedTime = -1f;

		internal bool InitialProbeStarted;

		internal bool ThirtySecondProbeStarted;

		internal int LastObservedPublicMemberCount = int.MinValue;

		internal float LastSeenTime;

		internal int ConsecutiveMisses;

		internal float InvalidSince = -1f;

		internal bool Removed;

		internal LobbySlot Slot;

		internal int CachedSlotInstanceId;

		internal Graphic[] CachedGraphics;

		internal Color[] CachedOriginalGraphicColors;

		internal Button CachedJoinButton;

		internal Image CachedInvalidOverlay;

		internal Image CachedFriendOverlay;

		internal TMP_Text CachedHostNameText;

		internal TMP_Text CachedFriendsText;

		internal LobbyInspectHover CachedInspectHover;

		internal bool HasOriginalJoinInteractable;

		internal bool OriginalJoinInteractable;

		internal bool UnicodeFallbackApplied;

		internal bool VisualStateInitialized;

		internal bool AppliedInvalid;

		internal bool AppliedBlockedHost;

		internal bool AppliedFriendHighlight;

		internal string AppliedName;

		internal string AppliedHostName;

		internal string AppliedFriendsText;

		internal bool AppliedShowHostName;

		internal bool AppliedShowFriends;

		internal int AppliedMemberCount = int.MinValue;

		internal int AppliedMaxMembers = int.MinValue;
	}
	internal static class StableLobbyManager
	{
		private static long cachedGameVersionNum = long.MinValue;

		private static string cachedGameVersionString = "";

		private static string cachedWrongVersionValue;

		private static string cachedWrongVersionReason;

		private const float DefaultBackgroundQueryInterval = 0.125f;

		private const float DefaultInvalidRemoveDelay = 30f;

		private const float MissingLobbyGraceSeconds = 5f;

		private const int MaxBackgroundLobbyResults = 100;

		private const float SlotSpacing = 42f;

		private const float DefaultLobbyScrollStep = 8f;

		private static ScrollRect cachedLobbyScrollRect;

		private static LobbyScrollWheelLimiter cachedLobbyScrollLimiter;

		private static int cachedLobbyScrollManagerInstanceId = -1;

		private static readonly Dictionary<ulong, LobbyState> States = new Dictionary<ulong, LobbyState>();

		private static readonly HashSet<ulong> SeenScratch = new HashSet<ulong>();

		private static readonly HashSet<ulong> VanillaLobbyIds = new HashSet<ulong>();

		private static readonly HashSet<ulong> HostPersonaRequestsInFlight = new HashSet<ulong>();

		private static readonly HashSet<ulong> HostPersonaRequestsCompleted = new HashSet<ulong>();

		private static readonly Dictionary<ulong, LobbySlot> ExistingSlotsScratch = new Dictionary<ulong, LobbySlot>();

		private static readonly List<LobbySlot> ExistingSlotsListScratch = new List<LobbySlot>();

		private static readonly List<LobbySlot> ReflowScratch = new List<LobbySlot>();

		private static readonly List<LobbySlot> FilterSlotsScratch = new List<LobbySlot>();

		private static readonly HashSet<int> FilterSeenRootsScratch = new HashSet<int>();

		private static readonly List<RectTransform> FilterVisibleRowsScratch = new List<RectTransform>();

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

		private static readonly Dictionary<ulong, string> PreviousFriendDisplaysScratch = new Dictionary<ulong, string>();

		private static readonly Dictionary<ulong, ulong> FriendPresenceCandidateLobby = new Dictionary<ulong, ulong>();

		private static readonly Dictionary<ulong, float> FriendPresenceCandidateSince = new Dictionary<ulong, float>();

		private static readonly HashSet<ulong> FriendPresenceSeenScratch = new HashSet<ulong>();

		private static readonly List<ulong> FriendPresenceRemoveScratch = new List<ulong>();

		private static SteamLobbyManager cachedManager;

		private static int cachedContainerChildCount = -1;

		private static bool uiScanRequested = true;

		private static readonly FieldInfo CurrentLobbyListField = AccessTools.Field(typeof(SteamLobbyManager), "currentLobbyList");

		private static readonly FieldInfo SteamLobbyEnteredEventField = FindSteamLobbyEnteredEventField();

		private static readonly List<Delegate> SuppressedBaseGameLobbyEnteredHandlers = new List<Delegate>();

		private static bool loggedMissingCurrentLobbyListField;

		private const float VanillaUiSettleDelay = 0.5f;

		private const string AppendedRowPrefix = "LobbyReworkAppended_";

		private static float vanillaUiSettlingUntil = -1f;

		private const float CurrentLobbyOwnerScanInterval = 0.25f;

		private static float nextCurrentLobbyOwnerScanTime = -1f;

		private const float FriendPresenceScanInterval = 0.5f;

		private static float nextFriendPresenceScanTime = -1f;

		private const string ProbePresenceFlagKey = "lobbyfilter_probe";

		private const string ProbePresenceLobbyKey = "lobbyfilter_probe_lobby";

		private const float FriendPresenceConfirmationSeconds = 0.75f;

		private static ulong advertisedProbeLobbyId;

		private const float ThirtySecondFollowupProbeDelay = 30f;

		private const float ProbeLingerSeconds = 1f;

		private const float ProbeQueueScanInterval = 0.25f;

		private static float nextProbeQueueScanTime = -1f;

		private static readonly Queue<ulong> LobbyProbeQueue = new Queue<ulong>();

		private static readonly HashSet<ulong> LobbyProbeQueuedIds = new HashSet<ulong>();

		private static bool lobbyProbeRunning;

		private static ulong activeProbeLobbyId;

		private static bool lobbyProbingDisabled;

		private static float nextQueryTime;

		private static bool queryRunning;

		private static bool loggedBrowserDetected;

		private static string lastAppliedNameSearch = null;

		private static int lastAppliedSearchChildCount = -1;

		private static int lastAppliedShowFilterMask = -1;

		private static bool lastAppliedHideSearchTags;

		private static bool localSearchDirty = true;

		private static bool localFilterWasActive;

		private const float EmptyFilterMessageDelay = 0.75f;

		private static float emptyFilterCandidateSince = -1f;

		private const string ShowDropdownName = "LobbyReworkShowDropdown";

		private static TMP_Dropdown showDropdown;

		private static GameObject patchedShowDropdownList;

		private static bool updatingShowDropdownItems;

		private static int browserControlsManagerInstanceId = -1;

		private static int selectedShowFilterMask;

		private static bool hideSearchTags;

		private static bool browserControlsSetupComplete;

		private const int ShowJoinableMask = 1;

		private const int ShowFriendsMask = 2;

		private const int ShowBlockedMask = 4;

		private const int ShowUnjoinableMask = 8;

		private static string cachedSearchTagsRaw;

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

		private static bool compatibilityControlsRemoved;

		private static bool detectedModsUiRemoved;

		private static bool challengeMoonUiRemoved;

		private static float nextCompatibilityUiSearchTime = -1f;

		private static readonly string[] ShowFilterBaseLabels = new string[6] { "Show: All", "Joinable", "Friends", "Blocked", "Unjoinable", "Hide tags" };

		private static float lastSuccessfulBackgroundQueryTime = -1f;

		private const int MaxUnicodeFallbackFailures = 3;

		private const string InvalidOverlayName = "LobbyReworkInvalidOverlay";

		private const string FriendOverlayName = "LobbyReworkFriendOverlay";

		private const string HostNameLabelName = "LobbyReworkHostName";

		private const string FriendsLabelName = "LobbyReworkFriends";

		private const string InspectIconName = "LobbyReworkInspectIcon";

		private const string InspectTooltipName = "LobbyReworkInspectTooltip";

		private const string InspectTooltipTextName = "LobbyReworkInspectTooltipText";

		private const string SteamProfileButtonName = "LobbyReworkSteamProfile";

		private static Texture2D inspectCircleTexture;

		private static Sprite inspectCircleSprite;

		private static Texture2D steamProfileTexture;

		private static Sprite steamProfileSprite;

		private const int SteamLogoTextureSize = 48;

		private const string SteamLogoAlphaBase64 = "AAAAAAAAAAAAAAAAAAAAAQMEAQAAAAAAAAAAAAABBAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEDAAAAABk8WW14eGxWNxYAAAABAwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAD2My/T///////////HGhTYAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAAtozf/////9/Pv7+/v8/v/////GXwUAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAwAAW9n///77/f7///////////78+/7//89QAAADAAAAAAAAAAAAAAAAAAAAAAAEABuw///7/f/////////////////////9/P//pBQABAAAAAAAAAAAAAAAAAAAAAQAQOT//P3///////////////////////////38/9w1AAQAAAAAAAAAAAAAAAAABABW+v/7///8+/3+/Pv+////////////////////+//0SQAEAAAAAAAAAAAAAAAEAFb//v3//v3//////////f////////////////////z/+kcAAwAAAAAAAAAAAAMAPfv9/f/+///EaTMqUaL4//3////////////////////9/vQyAAIAAAAAAAAAAgEY5//9//7992IAACIpAQAqzv/9/////////////////////P/eEAICAAAAAAAAAwCz//v///3+UQBt7P///5oEEtn+/f////////////////////v/pAADAAAAAAADAFb/+///+fyeAITccyksev/HATz+/f/////////////////////7/0cAAwAAAAEBCd7+/Pz8//8rB0QAAAAAAD3/eADK//z////////////////////8/tMFAgAAAAQAZv/4////2XYEAQAABAICBgC45QGK/Pr//////////////////////P9XAAQAAAEB0f//+7VSBwAAAAIBAAAABAOC/ABo//v9/////////////////////P7GAAIAAwBH/+OMLQAAAAMAAAAAAAAABgCn5gALhf//+/////////////////////79LgADAwBkag4AAAIDAQAAAAAAAAMDABv+igADAEXd//z+//////////////////v/fgAFAAAAAAAEAgAAAAAAAAEAAAAAP+bbDwECBAATpv///P////////////////z/wgACAAABBAEAAAAAAAEDAgADE3DT/7sbAAEAAAMAAGTy//v7+/3///////////7/7xAAAAAAAAAAAAACBAAAABoAAU9bLQAAAQAAAAABAwAqxP/////8/v/////////+/zEAAAAAAAAAAwMAAAhStPGqTBYAAAIBAAAAAAAAAAQABE1lltz///3////////8/08AAAAAAQQAAAAhfNj////////aEQIBAAAAAAAAAAIGAQAAAApl6v/9///////7/2QAAAEDAAAAQ6b0///9/P78/P3/oQAEAAAAAAAAAwAAAAAAAAAAI9T//f/////7/28AAAAAFmzM////+/3///////77/1QAAwAAAAADAB+M0+LHcQoAABvm/f3////7/2oAASSX6v///fz+///////////9/esYAQIAAAIAU/v8tZ3D/90pAgBR//z////7/1wAAG7///z9/////////////////P+yAAQAAwA3/7IUAAAAKtzjEAIAy//8///8/0gAAEf8+/////////////////////v/ZQAEAgDQ2AEABAQEABn8jAAAc//7/////ywAACL7//7///////////////////788yUAACH/XAAFAAAABgCa7QMAP//9//7/6w0AAQPZ//3////////////////////8/7sCAEX9LAECAAAABAFg/xQALf////z/vQACBACa/vv////////////////////9/uUKAD7/NQIDAAAABAJv/AwANP/+//v/eQAFAwBH//3////////////////////+//UdABH+iAAHAQECBQDEzgABVP/8//78KwACAQEG3f79/////////////////////P9WAQCW/y4AAAAAAFr/UgAAmP/7/P7CAAIAAAQAcv/7/////////////////////P+/AAMMzf1rGgskiP+bAAIS7P/+/P9UAAQAAAEBDub9/f////////////////////3/VwAEEKX///j//X0ABwCX//z8/tEEAgAAAAADAGL/+/////////////////////798TMAAQAkYHRUFQADAGX//P/7/0YAAwAAAAAAAwG+//z////////////////////+/+5PAAAAAAAAAAABef/9//v/pAADAAAAAAAAAgEe7f79/////////////////////f//qkIOAAAAF1fH//3//P/dEAICAAAAAAAAAAMAR/78/f////////////////////7+///lxr3M7v///P/9/vUxAAIAAAAAAAAAAAAEAF7//f3//////////////////////P7///////z9//z/+0kAAwAAAAAAAAAAAAAABABf/f/7///////////////////////9/Pz9/v//+//1SgAEAAAAAAAAAAAAAAAAAAQARun/+/3///////////////////////////38/902AAQAAAAAAAAAAAAAAAAAAAAEACC0///7/f/////////////////////9/P//pxUABAAAAAAAAAAAAAAAAAAAAAAAAwAAX9v///77/f7///////////79+/7//9JTAAADAAAAAAAAAAAAAAAAAAAAAAAAAAICAAxrz//////9+/v7+/v8/f/////JYgYAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAkCOzfT///////////TKiDkAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEDAAAAABo9W3B8fHBZOxkAAAAAAwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQMEAAAAAAAAAAAAAAABBAMAAAAAAAAAAAAAAAAAAAAA";

		private static readonly Color InvalidOverlayColor = new Color(0.95f, 0.08f, 0.08f, 0.18f);

		private static readonly Color FriendOverlayColor = new Color(0.08f, 0.8f, 0.18f, 0.18f);

		private static readonly Color FriendAccentColor = new Color(0.18f, 0.92f, 0.24f, 1f);

		private static TMP_FontAsset unicodeFallbackFont;

		private static Font unicodeFallbackSourceFont;

		private static int unicodeFallbackFailureCount;

		private static bool unicodeFallbackDisabled;

		private static string GetGameVersionString()
		{
			GameNetworkManager instance = GameNetworkManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			long num = instance.gameVersionNum;
			if (num != cachedGameVersionNum)
			{
				cachedGameVersionNum = num;
				cachedGameVersionString = num.ToString();
			}
			return cachedGameVersionString;
		}

		private static string GetWrongVersionReason(string version)
		{
			if (!string.Equals(version, cachedWrongVersionValue, StringComparison.Ordinal))
			{
				cachedWrongVersionValue = version;
				cachedWrongVersionReason = "Wrong game version (" + version + ")";
			}
			return cachedWrongVersionReason;
		}

		internal static void Tick()
		{
			SteamLobbyManager val = cachedManager;
			if ((Object)(object)val == (Object)null)
			{
				val = Object.FindObjectOfType<SteamLobbyManager>();
				if ((Object)(object)val != (Object)null)
				{
					cachedManager = val;
					uiScanRequested = true;
				}
			}
			if ((Object)(object)val == (Object)null || (Object)(object)val.levelListContainer == (Object)null || !((Component)val.levelListContainer).gameObject.activeInHierarchy)
			{
				return;
			}
			if (!loggedBrowserDetected)
			{
				loggedBrowserDetected = true;
				Plugin.LogInfo("Steam lobby browser detected; background cache refresh active.");
			}
			EnsureLobbyBrowserControls(val);
			PatchOpenShowSelectionMenu();
			EnsureComfortableLobbyScroll(val);
			int childCount = val.levelListContainer.childCount;
			if (uiScanRequested || childCount != cachedContainerChildCount)
			{
				ApplyKnownStatesToExistingSlots(val);
				cachedContainerChildCount = val.levelListContainer.childCount;
				uiScanRequested = false;
				localSearchDirty = true;
			}
			ApplyLocalNameSearch(val);
			RefreshHostInfoFromCurrentLobbyList(val);
			RefreshKnownHostInfoFromSteamPresence();
			QueueEligibleLobbyProbes();
			TryStartNextLobbyProbe();
			if (!(Time.unscaledTime < nextQueryTime))
			{
				float num = ((Plugin.PollInterval == null) ? 0.125f : Mathf.Max(0.01f, Plugin.PollInterval.Value));
				nextQueryTime = Time.unscaledTime + num;
				if (!queryRunning && !lobbyProbeRunning && !((Object)(object)GameNetworkManager.Instance == (Object)null) && !GameNetworkManager.Instance.waitingForLobbyDataRefresh)
				{
					RunBackgroundQuery(val);
				}
			}
		}

		internal static float GetLobbyScrollStep()
		{
			return Mathf.Clamp((Plugin.LobbyScrollStep == null) ? 8f : Plugin.LobbyScrollStep.Value, 0.25f, 42f);
		}

		private static void EnsureComfortableLobbyScroll(SteamLobbyManager manager)
		{
			if ((Object)(object)manager == (Object)null || (Object)(object)manager.levelListContainer == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)manager).GetInstanceID();
			if ((Object)(object)cachedLobbyScrollRect == (Object)null || cachedLobbyScrollManagerInstanceId != instanceID)
			{
				cachedLobbyScrollManagerInstanceId = instanceID;
				cachedLobbyScrollRect = ((Component)manager.levelListContainer).GetComponentInParent<ScrollRect>();
				if ((Object)(object)cachedLobbyScrollRect == (Object)null)
				{
					cachedLobbyScrollRect = ((Component)manager).GetComponentInChildren<ScrollRect>(true);
				}
				cachedLobbyScrollLimiter = null;
			}
			if ((Object)(object)cachedLobbyScrollRect == (Object)null)
			{
				return;
			}
			if (!Mathf.Approximately(cachedLobbyScrollRect.scrollSensitivity, 0f))
			{
				cachedLobbyScrollRect.scrollSensitivity = 0f;
			}
			if ((Object)(object)cachedLobbyScrollLimiter == (Object)null)
			{
				cachedLobbyScrollLimiter = ((Component)cachedLobbyScrollRect).GetComponent<LobbyScrollWheelLimiter>();
				if ((Object)(object)cachedLobbyScrollLimiter == (Object)null)
				{
					cachedLobbyScrollLimiter = ((Component)cachedLobbyScrollRect).gameObject.AddComponent<LobbyScrollWheelLimiter>();
				}
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo("Installed fixed lobby wheel scrolling at " + $"{GetLobbyScrollStep():0.###} px per wheel event.");
				}
			}
			cachedLobbyScrollLimiter.TargetScrollRect = cachedLobbyScrollRect;
			ref RectTransform fallbackContent = ref cachedLobbyScrollLimiter.FallbackContent;
			Transform levelListContainer = manager.levelListContainer;
			fallbackContent = (RectTransform)(object)((levelListContainer is RectTransform) ? levelListContainer : null);
		}

		private static async void RunBackgroundQuery(SteamLobbyManager manager)
		{
			queryRunning = true;
			try
			{
				string gameVersionString = GetGameVersionString();
				LobbyQuery val = SteamMatchmaking.LobbyList;
				LobbyQuery val2 = ((LobbyQuery)(ref val)).WithMaxResults(100);
				switch (manager.sortByDistanceSetting)
				{
				case 0:
					val = ((LobbyQuery)(ref val2)).FilterDistanceClose();
					val2 = ((LobbyQuery)(ref val)).WithKeyValue("vers", gameVersionString);
					break;
				case 1:
					val = ((LobbyQuery)(ref val2)).FilterDistanceFar();
					val2 = ((LobbyQuery)(ref val)).WithKeyValue("vers", gameVersionString);
					break;
				default:
					val = ((LobbyQuery)(ref val2)).FilterDistanceWorldwide();
					val2 = ((LobbyQuery)(ref val)).WithKeyValue("vers", gameVersionString);
					break;
				}
				val2 = ((LobbyQuery)(ref val2)).WithKeyValue("tag", "none");
				Lobby[] array = await ((LobbyQuery)(ref val2)).RequestAsync();
				if (array != null)
				{
					lastSuccessfulBackgroundQueryTime = Time.unscaledTime;
					ProcessSnapshot(manager, array);
				}
			}
			catch (Exception ex)
			{
				Plugin.LogWarning("Background lobby query failed: " + ex.Message);
			}
			finally
			{
				queryRunning = false;
			}
		}

		internal static void ObserveVanillaLobbyList(Lobby[] lobbies)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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)
			if (lobbies == null)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			vanillaUiSettlingUntil = unscaledTime + 0.5f;
			VanillaLobbyIds.Clear();
			for (int i = 0; i < lobbies.Length; i++)
			{
				Lobby lobby = lobbies[i];
				ulong num = SteamId.op_Implicit(((Lobby)(ref lobby)).Id);
				if (num == 0L)
				{
					continue;
				}
				VanillaLobbyIds.Add(num);
				try
				{
					((Lobby)(ref lobby)).Refresh();
				}
				catch
				{
				}
				if (!States.TryGetValue(num, out var value))
				{
					value = new LobbyState
					{
						LobbyId = num
					};
					States.Add(num, value);
				}
				bool invalid = value.Invalid;
				string reason = value.Reason;
				float invalidSince = value.InvalidSince;
				bool removed = value.Removed;
				value.Lobby = lobby;
				value.Name = SafeLobbyName(lobby);
				ObservePublicLobbyState(value, lobby, unscaledTime);
				UpdateHostInfo(lobby, value, authoritativeCurrentListResult: true);
				EvaluateLobby(lobby, value);
				ApplyBlockedHostProtection(value);
				if (invalid && !value.Invalid)
				{
					value.Invalid = true;
					value.Reason = reason;
					value.InvalidSince = invalidSince;
					value.Removed = removed;
					if (Plugin.LoggingEnabled)
					{
						Plugin.LogInfo($"Vanilla refresh preserved invalid state for lobby {num}: {reason}");
					}
				}
				else if (value.Invalid && (!invalid || reason != value.Reason))
				{
					Plugin.LogInfo($"Marked visible lobby {num} invalid immediately: {value.Reason}");
				}
			}
		}

		private static Lobby[] GetCurrentLobbyList(SteamLobbyManager manager)
		{
			if ((Object)(object)manager == (Object)null)
			{
				return null;
			}
			if (CurrentLobbyListField == null)
			{
				if (!loggedMissingCurrentLobbyListField)
				{
					loggedMissingCurrentLobbyListField = true;
					Plugin.LogWarning("SteamLobbyManager.currentLobbyList field was not found at runtime.");
				}
				return null;
			}
			try
			{
				return CurrentLobbyListField.GetValue(manager) as Lobby[];
			}
			catch (Exception ex)
			{
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo("Could not read SteamLobbyManager.currentLobbyList: " + ex.Message);
				}
				return null;
			}
		}

		private static void RefreshHostInfoFromCurrentLobbyList(SteamLobbyManager manager)
		{
			//IL_0042: 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_004b: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)manager == (Object)null || Time.unscaledTime < nextCurrentLobbyOwnerScanTime)
			{
				return;
			}
			nextCurrentLobbyOwnerScanTime = Time.unscaledTime + 0.25f;
			Lobby[] currentLobbyList = GetCurrentLobbyList(manager);
			if (currentLobbyList == null || currentLobbyList.Length == 0)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < currentLobbyList.Length; i++)
			{
				Lobby lobby = currentLobbyList[i];
				ulong num3 = SteamId.op_Implicit(((Lobby)(ref lobby)).Id);
				if (num3 != 0L)
				{
					if (!States.TryGetValue(num3, out var value))
					{
						value = new LobbyState
						{
							LobbyId = num3,
							Lobby = lobby,
							Name = SafeLobbyName(lobby)
						};
						States.Add(num3, value);
					}
					ObservePublicLobbyState(value, lobby, Time.unscaledTime);
					ulong hostSteamId = value.HostSteamId;
					string hostName = value.HostName;
					bool hostIsFriend = value.HostIsFriend;
					bool hostIsBlocked = value.HostIsBlocked;
					if (!value.HostConfirmedByProbe)
					{
						UpdateHostInfo(lobby, value, authoritativeCurrentListResult: true);
					}
					if (!string.IsNullOrWhiteSpace(value.HostName) && value.HostName != "Unknown" && value.HostName != "Unavailable")
					{
						num++;
					}
					if (hostSteamId != value.HostSteamId || hostName != value.HostName || hostIsFriend != value.HostIsFriend || hostIsBlocked != value.HostIsBlocked)
					{
						num2++;
						value.AppliedHostName = null;
						value.VisualStateInitialized = false;
					}
				}
			}
			if (Plugin.LoggingEnabled && num2 > 0)
			{
				Plugin.LogInfo($"currentLobbyList host refresh: resolved={num}/" + $"{currentLobbyList.Length}, changed={num2}.");
			}
		}

		private static string GetFriendsDisplayValue(LobbyState state)
		{
			if (state == null || state.FriendsInLobby.Count == 0)
			{
				return "";
			}
			List<string> friendDisplayNamesScratch = FriendDisplayNamesScratch;
			friendDisplayNamesScratch.Clear();
			foreach (string value in state.FriendsInLobby.Values)
			{
				friendDisplayNamesScratch.Add(value);
			}
			friendDisplayNamesScratch.Sort(StringComparer.OrdinalIgnoreCase);
			return string.Join(", ", friendDisplayNamesScratch);
		}

		private static void RefreshKnownHostInfoFromSteamPresence()
		{
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Invalid comparison between Unknown and I4
			if (Time.unscaledTime < nextFriendPresenceScanTime)
			{
				return;
			}
			nextFriendPresenceScanTime = Time.unscaledTime + 0.5f;
			Dictionary<ulong, string> previousFriendDisplaysScratch = PreviousFriendDisplaysScratch;
			previousFriendDisplaysScratch.Clear();
			foreach (KeyValuePair<ulong, LobbyState> state in States)
			{
				LobbyState value = state.Value;
				if (value != null)
				{
					previousFriendDisplaysScratch[value.LobbyId] = GetFriendsDisplayValue(value);
					value.FriendsInLobby.Clear();
				}
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			float unscaledTime = Time.unscaledTime;
			FriendPresenceSeenScratch.Clear();
			try
			{
				foreach (Friend friend in SteamFriends.GetFriends())
				{
					Friend current = friend;
					if (!TryGetPresenceLobbyId(current, out var lobbyId))
					{
						continue;
					}
					ulong num4 = SteamId.op_Implicit(current.Id);
					if (num4 == 0L)
					{
						continue;
					}
					FriendPresenceSeenScratch.Add(num4);
					LobbyState value2;
					if (IsFriendAdvertisingProbeForLobby(current, lobbyId))
					{
						RemoveFriendPresenceCandidate(num4);
						num2++;
						if (Plugin.LoggingEnabled)
						{
							Plugin.LogInfo("Ignored Steam friend '" + ((Friend)(ref current)).Name + "' " + $"in lobby {lobbyId}: their Lobby Filter " + "probe flag matches this lobby.");
						}
					}
					else if (!States.TryGetValue(lobbyId, out value2) || value2 == null)
					{
						RemoveFriendPresenceCandidate(num4);
					}
					else if (ConfirmFriendPresence(num4, lobbyId, unscaledTime))
					{
						string text = ((Friend)(ref current)).Name ?? "";
						string value3 = (IsUsefulPersonaName(text) ? text.Trim() : $"Steam {num4}");
						value2.FriendsInLobby[num4] = value3;
						num++;
						if (value2.HostConfirmedByProbe && value2.HostSteamId != 0L && num4 == value2.HostSteamId && !value2.HostIsFriend)
						{
							value2.HostIsFriend = true;
							value2.VisualStateInitialized = false;
							uiScanRequested = true;
						}
					}
				}
			}
			catch (Exception ex)
			{
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo("Steam friend presence scan failed: " + ex.Message);
				}
			}
			PurgeUnseenFriendPresenceCandidates();
			try
			{
				foreach (Friend item in SteamFriends.GetBlocked())
				{
					Friend current2 = item;
					if (!TryGetPresenceLobbyId(current2, out var lobbyId2) || !States.TryGetValue(lobbyId2, out var value4) || value4 == null)
					{
						continue;
					}
					ulong num5 = SteamId.op_Implicit(current2.Id);
					if (value4.HostConfirmedByProbe && value4.HostSteamId != 0L && num5 != 0L && num5 == value4.HostSteamId)
					{
						value4.HostIsBlocked = true;
						if ((int)((Friend)(ref current2)).Relationship == 6)
						{
							value4.HostIsFriend = true;
						}
						value4.VisualStateInitialized = false;
						uiScanRequested = true;
						localSearchDirty = true;
						num3++;
					}
				}
			}
			catch (Exception ex2)
			{
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo("Steam blocked-user presence scan failed: " + ex2.Message);
				}
			}
			int num6 = 0;
			foreach (KeyValuePair<ulong, LobbyState> state2 in States)
			{
				LobbyState value5 = state2.Value;
				if (value5 == null)
				{
					continue;
				}
				string value6 = "";
				previousFriendDisplaysScratch.TryGetValue(value5.LobbyId, out value6);
				string friendsDisplayValue = GetFriendsDisplayValue(value5);
				if (!(value6 == friendsDisplayValue))
				{
					num6++;
					value5.AppliedFriendsText = null;
					value5.AppliedShowFriends = false;
					value5.VisualStateInitialized = false;
					if ((Object)(object)value5.Slot != (Object)null)
					{
						UpdateFriendsDisplay(value5);
					}
				}
			}
			if (num6 > 0)
			{
				uiScanRequested = true;
				localSearchDirty = true;
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo($"Friend lists updated for {num6} " + $"lobby/lobbies; detectedMembers={num}, " + $"ignoredProbeFriends={num2}, " + $"blockedHosts={num3}.");
				}
			}
		}

		internal static void ClearLocalProbePresence()
		{
			try
			{
				SteamFriends.SetRichPresence("lobbyfilter_probe", "");
				SteamFriends.SetRichPresence("lobbyfilter_probe_lobby", "");
			}
			catch (Exception ex)
			{
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo("Could not clear Lobby Filter probe rich presence: " + ex.Message);
				}
			}
			advertisedProbeLobbyId = 0uL;
		}

		private static void AdvertiseLocalProbePresence(ulong lobbyId)
		{
			if (lobbyId == 0L)
			{
				ClearLocalProbePresence();
				return;
			}
			try
			{
				bool flag = SteamFriends.SetRichPresence("lobbyfilter_probe_lobby", lobbyId.ToString());
				bool flag2 = SteamFriends.SetRichPresence("lobbyfilter_probe", "1");
				advertisedProbeLobbyId = lobbyId;
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo("Advertising Lobby Filter probe for Steam lobby " + $"{lobbyId}; lobbyKeySet={flag}, flagSet={flag2}.");
				}
			}
			catch (Exception ex)
			{
				Plugin.LogWarning("Could not advertise Lobby Filter probe for lobby " + $"{lobbyId}: {ex.Message}");
			}
		}

		private static bool IsFriendAdvertisingProbeForLobby(Friend friend, ulong lobbyId)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			if (lobbyId == 0L || SteamId.op_Implicit(friend.Id) == 0L)
			{
				return false;
			}
			try
			{
				if (!string.Equals((((Friend)(ref friend)).GetRichPresence("lobbyfilter_probe") ?? "").Trim(), "1", StringComparison.Ordinal))
				{
					return false;
				}
				ulong result;
				return ulong.TryParse((((Friend)(ref friend)).GetRichPresence("lobbyfilter_probe_lobby") ?? "").Trim(), out result) && result == lobbyId;
			}
			catch
			{
				return false;
			}
		}

		private static bool ConfirmFriendPresence(ulong steamId, ulong lobbyId, float now)
		{
			if (steamId == 0L || lobbyId == 0L)
			{
				return false;
			}
			FriendPresenceSeenScratch.Add(steamId);
			if (!FriendPresenceCandidateLobby.TryGetValue(steamId, out var value) || value != lobbyId || !FriendPresenceCandidateSince.TryGetValue(steamId, out var value2))
			{
				FriendPresenceCandidateLobby[steamId] = lobbyId;
				FriendPresenceCandidateSince[steamId] = now;
				return false;
			}
			return now - value2 >= 0.75f;
		}

		private static void RemoveFriendPresenceCandidate(ulong steamId)
		{
			if (steamId != 0L)
			{
				FriendPresenceCandidateLobby.Remove(steamId);
				FriendPresenceCandidateSince.Remove(steamId);
			}
		}

		private static void PurgeUnseenFriendPresenceCandidates()
		{
			FriendPresenceRemoveScratch.Clear();
			foreach (KeyValuePair<ulong, ulong> item in FriendPresenceCandidateLobby)
			{
				if (!FriendPresenceSeenScratch.Contains(item.Key))
				{
					FriendPresenceRemoveScratch.Add(item.Key);
				}
			}
			for (int i = 0; i < FriendPresenceRemoveScratch.Count; i++)
			{
				RemoveFriendPresenceCandidate(FriendPresenceRemoveScratch[i]);
			}
		}

		private static bool TryGetPresenceLobbyId(Friend friend, out ulong lobbyId)
		{
			//IL_001b: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			lobbyId = 0uL;
			try
			{
				FriendGameInfo? gameInfo = ((Friend)(ref friend)).GameInfo;
				if (!gameInfo.HasValue)
				{
					return false;
				}
				FriendGameInfo value = gameInfo.Value;
				Lobby? lobby = ((FriendGameInfo)(ref value)).Lobby;
				if (!lobby.HasValue)
				{
					return false;
				}
				Lobby value2 = lobby.Value;
				lobbyId = SteamId.op_Implicit(((Lobby)(ref value2)).Id);
				return lobbyId != 0;
			}
			catch
			{
				return false;
			}
		}

		private static bool IsUsefulPersonaName(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return false;
			}
			string text = name.Trim();
			if (!text.Equals("Unknown", StringComparison.OrdinalIgnoreCase) && !text.Equals("Unavailable", StringComparison.OrdinalIgnoreCase))
			{
				return !text.Equals("[unknown]", StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}

		private static bool ApplyKnownHostIdentity(LobbyState state, Friend user, bool isFriend, bool isBlocked, string source)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (state == null)
			{
				return false;
			}
			ulong hostSteamId = state.HostSteamId;
			string hostName = state.HostName;
			bool hostIsFriend = state.HostIsFriend;
			bool hostIsBlocked = state.HostIsBlocked;
			ulong num = SteamId.op_Implicit(user.Id);
			string text = ((Friend)(ref user)).Name ?? "";
			if (string.Equals(source, "Steam lobby probe", StringComparison.Ordinal) && num != 0L)
			{
				if (!state.HostConfirmedByProbe || state.HostSteamId == 0L || state.HostSteamId == num)
				{
					state.HostSteamId = num;
					state.HostConfirmedByProbe = true;
				}
			}
			else if (!state.HostConfirmedByProbe && num != 0L)
			{
				state.HostSteamId = num;
			}
			if (IsUsefulPersonaName(text))
			{
				if (!state.HostConfirmedByProbe || num == 0L || num == state.HostSteamId)
				{
					state.HostName = text.Trim();
				}
			}
			else if (!IsUsefulPersonaName(state.HostName))
			{
				state.HostName = ((state.HostSteamId == 0L) ? "Unavailable" : "Unknown");
			}
			if (!state.HostConfirmedByProbe || num == 0L || num == state.HostSteamId)
			{
				state.HostIsFriend = isFriend;
				state.HostIsBlocked = isBlocked;
			}
			if (hostSteamId == state.HostSteamId && !(hostName != state.HostName) && hostIsFriend == state.HostIsFriend && hostIsBlocked == state.HostIsBlocked)
			{
				return false;
			}
			state.AppliedHostName = null;
			state.VisualStateInitialized = false;
			uiScanRequested = true;
			localSearchDirty = true;
			if (Plugin.LoggingEnabled)
			{
				Plugin.LogInfo($"Host matched by {source} for lobby {state.LobbyId}: " + $"'{state.HostName}' ({state.HostSteamId}), " + $"friend={state.HostIsFriend}, blocked={state.HostIsBlocked}.");
			}
			return true;
		}

		internal static void DisableLobbyProbing()
		{
			lobbyProbingDisabled = true;
			LobbyProbeQueue.Clear();
			LobbyProbeQueuedIds.Clear();
		}

		private static void ObservePublicLobbyState(LobbyState state, Lobby lobby, float now)
		{
			if (state == null || state.LobbyId == 0L)
			{
				return;
			}
			if (state.FirstDetectedTime < 0f)
			{
				state.FirstDetectedTime = now;
			}
			int memberCount = ((Lobby)(ref lobby)).MemberCount;
			if (state.LastObservedPublicMemberCount == int.MinValue)
			{
				state.LastObservedPublicMemberCount = memberCount;
			}
			else
			{
				if (memberCount == state.LastObservedPublicMemberCount)
				{
					return;
				}
				int lastObservedPublicMemberCount = state.LastObservedPublicMemberCount;
				if (lobbyProbeRunning && activeProbeLobbyId == state.LobbyId)
				{
					return;
				}
				state.LastObservedPublicMemberCount = memberCount;
				if (!Plugin.MinimizeProbeExposureEnabled)
				{
					LobbyInspectHover cachedInspectHover = state.CachedInspectHover;
					if (!((Object)(object)cachedInspectHover == (Object)null) && cachedInspectHover.IsHovered)
					{
						QueueLobbyProbe(state, "Inspect hovered and player count changed " + $"{lastObservedPublicMemberCount} -> {memberCount}");
					}
				}
			}
		}

		private static string MarkProbeLifecycleStarted(LobbyState state)
		{
			if (state == null)
			{
				return "unknown";
			}
			float unscaledTime = Time.unscaledTime;
			if (!state.InitialProbeStarted)
			{
				state.InitialProbeStarted = true;
				return "initial detection";
			}
			if (!Plugin.MinimizeProbeExposureEnabled && !state.ThirtySecondProbeStarted && state.FirstDetectedTime >= 0f && unscaledTime - state.FirstDetectedTime >= 30f)
			{
				state.ThirtySecondProbeStarted = true;
				return "30-second follow-up";
			}
			return "hovered Inspect player-count refresh";
		}

		private static void QueueEligibleLobbyProbes()
		{
			if (lobbyProbingDisabled)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime < nextProbeQueueScanTime)
			{
				return;
			}
			nextProbeQueueScanTime = unscaledTime + 0.25f;
			foreach (KeyValuePair<ulong, LobbyState> state in States)
			{
				LobbyState value = state.Value;
				if (IsLobbyProbeEligible(value))
				{
					if (!value.InitialProbeStarted)
					{
						QueueLobbyProbe(value, "initial detection");
					}
					else if (!Plugin.MinimizeProbeExposureEnabled && !value.ThirtySecondProbeStarted && value.FirstDetectedTime >= 0f && unscaledTime - value.FirstDetectedTime >= 30f)
					{
						QueueLobbyProbe(value, "30-second follow-up");
					}
				}
			}
		}

		private static void QueueLobbyProbe(LobbyState state, string reason)
		{
			if (!lobbyProbingDisabled && IsLobbyProbeEligible(state) && !LobbyProbeQueuedIds.Contains(state.LobbyId) && (!lobbyProbeRunning || activeProbeLobbyId != state.LobbyId))
			{
				LobbyProbeQueue.Enqueue(state.LobbyId);
				LobbyProbeQueuedIds.Add(state.LobbyId);
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo($"Queued Steam lobby probe for {state.LobbyId} " + "('" + state.Name + "'): " + reason + ".");
				}
			}
		}

		private static bool IsLobbyProbeEligible(LobbyState state)
		{
			if (state == null || state.LobbyId == 0L || state.Invalid || state.Removed)
			{
				return false;
			}
			return true;
		}

		private static FieldInfo FindSteamLobbyEnteredEventField()
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(SteamMatchmaking), "OnLobbyEntered");
			if (fieldInfo != null)
			{
				return fieldInfo;
			}
			FieldInfo[] fields = typeof(SteamMatchmaking).GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo2 in fields)
			{
				if (!(fieldInfo2 == null) && fieldInfo2.Name.IndexOf("LobbyEntered", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return fieldInfo2;
				}
			}
			return null;
		}

		private static bool IsBaseGameLobbyEnteredHandler(Delegate handler)
		{
			if ((object)handler == null)
			{
				return false;
			}
			Assembly assembly = typeof(GameNetworkManager).Assembly;
			try
			{
				MethodInfo method = handler.Method;
				if (method != null && method.DeclaringType != null && method.DeclaringType.Assembly == assembly)
				{
					return true;
				}
			}
			catch
			{
			}
			try
			{
				object target = handler.Target;
				if (target != null && target.GetType().Assembly == assembly)
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool TrySuppressBaseGameLobbyEnteredHandlers()
		{
			SuppressedBaseGameLobbyEnteredHandlers.Clear();
			if (SteamLobbyEnteredEventField == null)
			{
				Plugin.LogWarning("Could not find SteamMatchmaking.OnLobbyEntered's backing field. Lobby probing has been disabled for safety.");
				DisableLobbyProbing();
				return false;
			}
			try
			{
				if (!(SteamLobbyEnteredEventField.GetValue(null) is Delegate obj))
				{
					if (Plugin.LoggingEnabled)
					{
						Plugin.LogInfo("SteamMatchmaking.OnLobbyEntered has no subscribers; no suppression is required for this probe.");
					}
					return true;
				}
				Delegate obj2 = obj;
				Delegate[] invocationList = obj.GetInvocationList();
				foreach (Delegate obj3 in invocationList)
				{
					if (IsBaseGameLobbyEnteredHandler(obj3))
					{
						obj2 = Delegate.Remove(obj2, obj3);
						SuppressedBaseGameLobbyEnteredHandlers.Add(obj3);
					}
				}
				if (SuppressedBaseGameLobbyEnteredHandlers.Count == 0)
				{
					if (Plugin.LoggingEnabled)
					{
						Plugin.LogInfo("SteamMatchmaking.OnLobbyEntered has subscribers, but none from Assembly-CSharp; no base-game suppression is required for this probe.");
					}
					return true;
				}
				SteamLobbyEnteredEventField.SetValue(null, obj2);
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo("Temporarily suppressed " + $"{SuppressedBaseGameLobbyEnteredHandlers.Count} " + "base-game OnLobbyEntered handler(s) for probe.");
				}
				return true;
			}
			catch (Exception ex)
			{
				Plugin.LogWarning("Could not suppress Steam lobby-enter subscribers: " + ex.Message + ". Lobby probing has been disabled.");
				SuppressedBaseGameLobbyEnteredHandlers.Clear();
				DisableLobbyProbing();
				return false;
			}
		}

		private static void RestoreBaseGameLobbyEnteredHandlers()
		{
			if (SuppressedBaseGameLobbyEnteredHandlers.Count == 0)
			{
				return;
			}
			if (SteamLobbyEnteredEventField == null)
			{
				SuppressedBaseGameLobbyEnteredHandlers.Clear();
				return;
			}
			try
			{
				Delegate obj = SteamLobbyEnteredEventField.GetValue(null) as Delegate;
				for (int i = 0; i < SuppressedBaseGameLobbyEnteredHandlers.Count; i++)
				{
					Delegate obj2 = SuppressedBaseGameLobbyEnteredHandlers[i];
					bool flag = false;
					if ((object)obj != null)
					{
						Delegate[] invocationList = obj.GetInvocationList();
						for (int j = 0; j < invocationList.Length; j++)
						{
							if (invocationList[j] == obj2)
							{
								flag = true;
								break;
							}
						}
					}
					if (!flag)
					{
						obj = Delegate.Combine(obj, obj2);
					}
				}
				SteamLobbyEnteredEventField.SetValue(null, obj);
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo("Restored " + $"{SuppressedBaseGameLobbyEnteredHandlers.Count} " + "base-game OnLobbyEntered handler(s) after probe.");
				}
			}
			catch (Exception ex)
			{
				Plugin.LogWarning("Could not restore Steam lobby-enter subscribers: " + ex.Message);
			}
			finally
			{
				SuppressedBaseGameLobbyEnteredHandlers.Clear();
			}
		}

		private static void TryStartNextLobbyProbe()
		{
			if (lobbyProbingDisabled || lobbyProbeRunning || queryRunning)
			{
				return;
			}
			GameNetworkManager instance = GameNetworkManager.Instance;
			if ((Object)(object)instance == (Object)null || instance.waitingForLobbyDataRefresh || (Object)(object)StartOfRound.Instance != (Object)null || instance.isHostingGame)
			{
				return;
			}
			while (LobbyProbeQueue.Count > 0)
			{
				ulong num = LobbyProbeQueue.Dequeue();
				LobbyProbeQueuedIds.Remove(num);
				if (States.TryGetValue(num, out var value) && IsLobbyProbeEligible(value))
				{
					ProbeLobbyOnce(value);
					break;
				}
			}
		}

		private static bool TryGetDefinitiveProbeFailureReason(RoomEnter result, out string reason)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected I4, but got Unknown
			switch (result - 2)
			{
			case 0:
				reason = "Steam reports lobby no longer exists";
				return true;
			case 1:
				reason = "Steam reports lobby is not joinable";
				return true;
			case 2:
				reason = "Lobby is full (confirmed by Steam)";
				return true;
			case 4:
				reason = "Steam denied join: banned from lobby";
				return true;
			case 5:
				reason = "Steam denied join: limited";
				return true;
			case 6:
				reason = "Steam denied join: clan disabled";
				return true;
			case 7:
				reason = "Steam denied join: community ban";
				return true;
			case 8:
				reason = "Steam denied join: lobby member blocked you";
				return true;
			case 9:
				reason = "Steam denied join: blocked lobby member";
				return true;
			default:
				reason = null;
				return false;
			}
		}

		private static void ApplyDefinitiveProbeFailure(ulong lobbyId, RoomEnter result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (TryGetDefinitiveProbeFailureReason(result, out var reason) && States.TryGetValue(lobbyId, out var value) && value != null)
			{
				value.ProbeJoinRejected = true;
				value.ProbeJoinRejectReason = reason;
				SetInvalid(value, reason);
				ApplyBlockedHostProtection(value);
				uiScanRequested = true;
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo($"Steam probe confirmed lobby {lobbyId} unjoinable: " + reason + ".");
				}
			}
		}

		internal static string GetLobbyInspectText(ulong lobbyId)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (lobbyId == 0L || !States.TryGetValue(lobbyId, out var value) || value == null)
			{
				return "<color=#D8661A>> MEMBERS</color>" + Environment.NewLine + "<color=#A9A39B>UNAVAILABLE</color>";
			}
			string text = ColorUtility.ToHtmlStringRGB(GetNormalLobbyAccentColor(value));
			if (!value.MembersKnown)
			{
				return "<color=#" + text + ">> MEMBERS</color>" + Environment.NewLine + "<color=#A9A39B>WAITING FOR PROBE...</color>";
			}
			List<KeyValuePair<ulong, string>> list = new List<KeyValuePair<ulong, string>>();
			PopulateSortedLobbyMembers(value, list);
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<color=#");
			stringBuilder.Append(text);
			stringBuilder.Append(">> MEMBERS [");
			stringBuilder.Append(list.Count);
			stringBuilder.Append("]</color>");
			if (list.Count == 0)
			{
				stringBuilder.AppendLine();
				stringBuilder.Append("<color=#A9A39B>NO NON-PROBE MEMBERS FOUND</color>");
				return stringBuilder.ToString();
			}
			for (int i = 0; i < list.Count; i++)
			{
				KeyValuePair<ulong, string> keyValuePair = list[i];
				string value2 = (string.IsNullOrWhiteSpace(keyValuePair.Value) ? $"Steam {keyValuePair.Key}" : keyValuePair.Value);
				stringBuilder.AppendLine();
				stringBuilder.Append("<color=#");
				stringBuilder.Append(text);
				stringBuilder.Append(">> ");
				stringBuilder.Append(value2);
				if (value.HostSteamId != 0L && keyValuePair.Key == value.HostSteamId)
				{
					stringBuilder.Append("  [HOST]");
				}
				stringBuilder.Append("</color>");
			}
			return stringBuilder.ToString();
		}

		internal static bool GetLobbyInspectMembers(ulong lobbyId, List<KeyValuePair<ulong, string>> destination)
		{
			if (destination == null)
			{
				return false;
			}
			destination.Clear();
			if (lobbyId == 0L || !States.TryGetValue(lobbyId, out var value) || value == null || !value.MembersKnown)
			{
				return false;
			}
			PopulateSortedLobbyMembers(value, destination);
			return true;
		}

		private static void PopulateSortedLobbyMembers(LobbyState state, List<KeyValuePair<ulong, string>> destination)
		{
			destination.Clear();
			if (state == null)
			{
				return;
			}
			foreach (KeyValuePair<ulong, string> item in state.MembersInLobby)
			{
				destination.Add(item);
			}
			destination.Sort(delegate(KeyValuePair<ulong, string> a, KeyValuePair<ulong, string> b)
			{
				bool flag = state.HostSteamId != 0L && a.Key == state.HostSteamId;
				bool flag2 = state.HostSteamId != 0L && b.Key == state.HostSteamId;
				return (flag != flag2) ? ((!flag) ? 1 : (-1)) : StringComparer.OrdinalIgnoreCase.Compare(a.Value ?? "", b.Value ?? "");
			});
		}

		private static string GetMembersDisplayValue(LobbyState state)
		{
			if (state == null || !state.MembersKnown)
			{
				return "";
			}
			List<string> list = new List<string>(state.MembersInLobby.Values);
			list.Sort(StringComparer.OrdinalIgnoreCase);
			return string.Join(Environment.NewLine, list);
		}

		private static void RefreshLobbyInspect(LobbyState state)
		{
			if (LobbyInfoEnabled() && state != null && !((Object)(object)state.CachedInspectHover == (Object)null))
			{
				state.CachedInspectHover.LobbyId = state.LobbyId;
				state.CachedInspectHover.RefreshIfVisible();
			}
		}

		private static void CaptureMembersFromProbe(Lobby lobby, LobbyState state)
		{
			//IL_003b: 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_0042: 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)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if (state == null)
			{
				return;
			}
			string membersDisplayValue = GetMembersDisplayValue(state);
			bool membersKnown = state.MembersKnown;
			state.MembersInLobby.Clear();
			state.MembersKnown = false;
			int num = 0;
			try
			{
				foreach (Friend member in ((Lobby)(ref lobby)).Members)
				{
					Friend current = member;
					if (SteamId.op_Implicit(current.Id) == 0L)
					{
						continue;
					}
					if (((Friend)(ref current)).IsMe)
					{
						num++;
					}
					else if (IsFriendAdvertisingProbeForLobby(current, state.LobbyId))
					{
						num++;
						if (Plugin.LoggingEnabled)
						{
							Plugin.LogInfo("Ignored probe member '" + ((Friend)(ref current)).Name + "' " + $"while inspecting lobby {state.LobbyId}.");
						}
					}
					else
					{
						string text = ((Friend)(ref current)).Name ?? "";
						string value = (IsUsefulPersonaName(text) ? text.Trim() : $"Steam {current.Id}");
						state.MembersInLobby[SteamId.op_Implicit(current.Id)] = value;
					}
				}
				state.MembersKnown = true;
			}
			catch (Exception ex)
			{
				state.MembersInLobby.Clear();
				state.MembersKnown = false;
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo("Could not enumerate probe members for lobby " + $"{state.LobbyId}: {ex.Message}");
				}
			}
			string membersDisplayValue2 = GetMembersDisplayValue(state);
			if (membersKnown != state.MembersKnown || membersDisplayValue != membersDisplayValue2)
			{
				RefreshLobbyInspect(state);
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo($"Probe member snapshot for lobby {state.LobbyId}: " + $"realMembers={state.MembersInLobby.Count}, " + $"ignoredProbes={num}.");
				}
			}
		}

		private static async void ProbeLobbyOnce(LobbyState state)
		{
			if (state == null || !IsLobbyProbeEligible(state) || lobbyProbeRunning)
			{
				return;
			}
			ulong lobbyId = state.LobbyId;
			Lobby probeLobby = state.Lobby;
			lobbyProbeRunning = true;
			activeProbeLobbyId = lobbyId;
			string text = MarkProbeLifecycleStarted(state);
			bool enteredLobby = false;
			bool handlersSuppressed = false;
			bool probePresenceAttempted = false;
			try
			{
				handlersSuppressed = TrySuppressBaseGameLobbyEnteredHandlers();
				if (!handlersSuppressed)
				{
					return;
				}
				if (States.TryGetValue(lobbyId, out var value) && value != null)
				{
					value.LastProbeTime = Time.unscaledTime;
				}
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo($"Probing Steam lobby {lobbyId} for host/joinability " + "(" + text + ").");
				}
				probePresenceAttempted = true;
				AdvertiseLocalProbePresence(lobbyId);
				RoomEnter val = await ((Lobby)(ref probeLobby)).Join();
				if ((int)val != 1)
				{
					if (Plugin.LoggingEnabled)
					{
						Plugin.LogInfo($"Steam lobby probe {lobbyId} did not enter: {val}.");
					}
					if (States.TryGetValue(lobbyId, out var value2) && value2 != null)
					{
						value2.MembersInLobby.Clear();
						value2.MembersKnown = false;
						RefreshLobbyInspect(value2);
					}
					ApplyDefinitiveProbeFailure(lobbyId, val);
					return;
				}
				enteredLobby = true;
				try
				{
					((Lobby)(ref probeLobby)).Refresh();
				}
				catch
				{
				}
				Friend owner = ((Lobby)(ref probeLobby)).Owner;
				ulong num = SteamId.op_Implicit(owner.Id);
				string text2 = ((Friend)(ref owner)).Name ?? "";
				Relationship relationship = ((Friend)(ref owner)).Relationship;
				bool isBlocked = (int)relationship == 5 || (int)relationship == 6;
				bool isFriend = (int)relationship == 3 || (int)relationship == 6 || ((Friend)(ref owner)).IsFriend;
				if (States.TryGetValue(lobbyId, out var value3) && value3 != null)
				{
					value3.ProbeJoinRejected = false;
					value3.ProbeJoinRejectReason = null;
					CaptureMembersFromProbe(probeLobby, value3);
					ApplyKnownHostIdentity(value3, owner, isFriend, isBlocked, "Steam lobby probe");
					ApplyBlockedHostProtection(value3);
					if (num != 0L && !IsUsefulPersonaName(text2))
					{
						RequestHostPersona(owner);
					}
				}
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo($"Steam lobby probe {lobbyId} resolved host " + $"'{text2}' ({num}), relationship={relationship}.");
				}
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo($"Lingering in Steam lobby {lobbyId} for " + $"{1f:0.###}s before leaving.");
				}
				await Task.Delay(TimeSpan.FromSeconds(1.0));
			}
			catch (Exception ex)
			{
				Plugin.LogWarning($"Steam lobby probe {lobbyId} failed: {ex.Message}");
			}
			finally
			{
				if (enteredLobby)
				{
					try
					{
						((Lobby)(ref probeLobby)).Leave();
					}
					catch (Exception ex2)
					{
						Plugin.LogWarning($"Could not leave probed Steam lobby {lobbyId}: " + ex2.Message);
					}
				}
				if (probePresenceAttempted)
				{
					ClearLocalProbePresence();
				}
				if (handlersSuppressed)
				{
					RestoreBaseGameLobbyEnteredHandlers();
				}
				activeProbeLobbyId = 0uL;
				lobbyProbeRunning = false;
				uiScanRequested = true;
				TryStartNextLobbyProbe();
			}
		}

		private static void ProcessSnapshot(SteamLobbyManager manager, Lobby[] lobbies)
		{
			//IL_001b: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_0088: 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_009c: 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)
			float unscaledTime = Time.unscaledTime;
			HashSet<ulong> seenScratch = SeenScratch;
			seenScratch.Clear();
			for (int i = 0; i < lobbies.Length; i++)
			{
				Lobby lobby = lobbies[i];
				ulong num = SteamId.op_Implicit(((Lobby)(ref lobby)).Id);
				if (num == 0L)
				{
					continue;
				}
				seenScratch.Add(num);
				if (!States.TryGetValue(num, out var value))
				{
					value = new LobbyState
					{
						LobbyId = num
					};
					States.Add(num, value);
				}
				bool invalid = value.Invalid;
				string reason = value.Reason;
				value.Lobby = lobby;
				value.Name = SafeLobbyName(lobby);
				ObservePublicLobbyState(value, lobby, unscaledTime);
				UpdateHostInfo(lobby, value, authoritativeCurrentListResult: false);
				value.LastSeenTime = unscaledTime;
				value.ConsecutiveMisses = 0;
				EvaluateLobby(lobby, value);
				ApplyBlockedHostProtection(value);
				if (value.Invalid && (!invalid || reason != value.Reason))
				{
					if (Plugin.LoggingEnabled)
					{
						Plugin.LogInfo($"Marked lobby {num} invalid: {value.Reason}");
					}
				}
				else if (!value.Invalid && invalid && Plugin.LoggingEnabled)
				{
					Plugin.LogInfo($"Lobby {num} became valid again; restored row.");
				}
			}
			foreach (KeyValuePair<ulong, LobbyState> state in States)
			{
				LobbyState value2 = state.Value;
				if (seenScratch.Contains(value2.LobbyId))
				{
					continue;
				}
				value2.ConsecutiveMisses++;
				if (value2.LastSeenTime > 0f && unscaledTime - value2.LastSeenTime >= 5f && (!value2.Invalid || value2.Reason != "No longer returned by Steam"))
				{
					SetInvalid(value2, "No longer returned by Steam");
					if (Plugin.LoggingEnabled)
					{
						Plugin.LogInfo($"Marked lobby {value2.LobbyId} invalid: {value2.Reason}");
					}
				}
			}
			ApplySnapshotToUi(manager, lobbies);
			nextProbeQueueScanTime = -1f;
			if (HasActiveLocalFilter(manager))
			{
				localSearchDirty = true;
			}
		}

		private static void UpdateHostInfo(Lobby lobby, LobbyState state, bool authoritativeCurrentListResult)
		{
			//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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00f2: Invalid comparison between Unknown and I4
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Invalid comparison between Unknown and I4
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Invalid comparison between Unknown and I4
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Invalid comparison between Unknown and I4
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			if (state == null || (authoritativeCurrentListResult && state.HostConfirmedByProbe))
			{
				return;
			}
			ulong hostSteamId = state.HostSteamId;
			string hostName = state.HostName;
			bool hostIsFriend = state.HostIsFriend;
			bool hostIsBlocked = state.HostIsBlocked;
			try
			{
				Friend owner = ((Lobby)(ref lobby)).Owner;
				string text = ((Friend)(ref owner)).Name ?? "";
				Relationship relationship = ((Friend)(ref owner)).Relationship;
				ulong num = SteamId.op_Implicit(owner.Id);
				bool flag = !string.IsNullOrWhiteSpace(text) || (int)relationship != 0 || num != 0;
				if (authoritativeCurrentListResult || flag)
				{
					if (num != 0L)
					{
						state.HostSteamId = num;
					}
					if (IsUsefulPersonaName(text))
					{
						state.HostName = text.Trim();
					}
					else if (authoritativeCurrentListResult && state.HostSteamId == 0L && (int)relationship == 0 && !state.HostIsFriend && !state.HostIsBlocked)
					{
						state.HostName = "Unavailable";
					}
					else if (string.IsNullOrWhiteSpace(state.HostName))
					{
						state.HostName = "Unknown";
					}
					if (flag)
					{
						state.HostIsBlocked = (int)relationship == 5 || (int)relationship == 6;
						state.HostIsFriend = (int)relationship == 3 || (int)relationship == 6;
					}
					if (!IsUsefulPersonaName(text) && num != 0L)
					{
						RequestHostPersona(owner);
					}
					if (string.IsNullOrWhiteSpace(text) && !state.HostIsFriend && !state.HostIsBlocked && num == 0 && authoritativeCurrentListResult && state.HostSteamId == 0L && !state.HostIsFriend && !state.HostIsBlocked)
					{
						state.HostName = "Unavailable";
					}
					if (Plugin.LoggingEnabled && (hostSteamId != state.HostSteamId || hostName != state.HostName || hostIsFriend != state.HostIsFriend || hostIsBlocked != state.HostIsBlocked))
					{
						Plugin.LogInfo($"Host data for lobby {state.LobbyId}: " + "name='" + state.HostName + "', rawName='" + text + "', " + $"id={num}, relationship={relationship}, " + $"friend={state.HostIsFriend}, blocked={state.HostIsBlocked}.");
					}
				}
			}
			catch (Exception ex)
			{
				if (Plugin.LoggingEnabled && authoritativeCurrentListResult)
				{
					Plugin.LogInfo($"Host read failed for lobby {state.LobbyId}: " + ex.Message);
				}
			}
		}

		private static async void RequestHostPersona(Friend owner)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			ulong steamId = SteamId.op_Implicit(owner.Id);
			if (steamId == 0L || HostPersonaRequestsInFlight.Contains(steamId) || HostPersonaRequestsCompleted.Contains(steamId))
			{
				return;
			}
			HostPersonaRequestsInFlight.Add(steamId);
			try
			{
				await ((Friend)(ref owner)).RequestInfoAsync();
				string text = ((Friend)(ref owner)).Name ?? "";
				bool flag = IsUsefulPersonaName(text);
				if (flag)
				{
					foreach (KeyValuePair<ulong, LobbyState> state in States)
					{
						LobbyState value = state.Value;
						if (value != null && value.HostSteamId == steamId)
						{
							value.HostName = text.Trim();
							Relationship relationship = ((Friend)(ref owner)).Relationship;
							value.HostIsFriend = (int)relationship == 3 || (int)relationship == 6 || ((Friend)(ref owner)).IsFriend;
							value.HostIsBlocked = (int)relationship == 5 || (int)relationship == 6;
							value.AppliedHostName = null;
							value.VisualStateInitialized = false;
							uiScanRequested = true;
						}
					}
					if (Plugin.LoggingEnabled)
					{
						Plugin.LogInfo($"Steam persona resolved host {steamId} as '{text}'.");
					}
				}
				if (flag)
				{
					HostPersonaRequestsCompleted.Add(steamId);
				}
				else if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo($"Steam persona for host {steamId} is still unresolved " + "('" + text + "'); it will be retried on a later probe.");
				}
			}
			catch (Exception ex)
			{
				if (Plugin.LoggingEnabled)
				{
					Plugin.LogInfo($"Steam persona request failed for host {steamId}: " + ex.Message);
				}
			}
			finally
			{
				HostPersonaRequestsInFlight.Remove(steamId);
			}
		}

		private static bool FriendHighlightEnabled(LobbyState state)
		{
			if (state != null && Plugin.FriendLobbies != null && Plugin.FriendLobbies.Value && (state.HostIsFriend || state.FriendsInLobby.Count > 0))
			{
				return !state.HostIsBlocked;
			}
			return false;
		}

		private static bool BlockedHostVisualEnabled(LobbyState state)
		{
			if (state != null && Plugin.BlockedLobbies != null && Plugin.BlockedLobbies.Value)
			{
				return state.HostIsBlocked;
			}
			return false;
		}

		private static bool HostNameEnabled()
		{
			if (Plugin.ShowHostName != null)
			{
				return Plugin.ShowHostName.Value;
			}
			return false;
		}

		private static void ApplyBlockedHostProtection(LobbyState state)
		{
			if (BlockedHostVisualEnabled(state))
			{
				state.Removed = false;
				if (state.Invalid)
				{
					state.InvalidSince = Time.unscaledTime;
				}
			}
		}

		private static void EvaluateLobby(Lobby lobby, LobbyState state)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(state.Name))
			{
				SetInvalid(state, "Lobby has no name");
				return;
			}
			string text = SafeGetData(lobby, "vers");
			if (!string.IsNullOrEmpty(text))
			{
				string gameVersionString = GetGameVersionString();
				if (gameVersionString != null && !string.Equals(text, gameVersionString, StringComparison.Ordinal))
				{
					SetInvalid(state, GetWrongVersionReason(text));
					return;
				}
			}
			if (string.Equals(SafeGetData(lobby, "joinable"), "false", StringComparison.OrdinalIgnoreCase))
			{
				SetInvalid(state, "Host has already landed / lobby not joinable");
			}
			else if (((Lobby)(ref lobby)).MemberCount < 1)
			{
				SetInvalid(state, "Lobby has no members");
			}
			else if (((Lobby)(ref lobby)).MemberCount >= ((Lobby)(ref lobby)).MaxMembers)
			{
				SetInvalid(state, "Lobby is full");
			}
			else if (state.ProbeJoinRejected)
			{
				SetInvalid(state, string.IsNullOrWhiteSpace(state.ProbeJoinRejectReason) ? "Steam probe confirmed lobby is unjoinable" : state.ProbeJoinRejectReason);
			}
			else
			{
				SetValid(state);
			}
		}

		private static void SetValid(LobbyState state)
		{
			bool num = state.Invalid || state.Removed;
			state.Invalid = false;
			state.Reason = "";
			state.InvalidSince = -1f;
			state.Removed = false;
			if (num)
			{
				localSearchDirty = true;
			}
		}

		private static void SetInvalid(LobbyState state, string reason)
		{
			bool num = !state.Invalid || state.Reason != reason;
			if (!state.Invalid || state.InvalidSince < 0f)
			{
				state.InvalidSince = Time.unscaledTime;
			}
			state.Invalid = true;
			state.Reason = reason;
			if (num)
			{
				localSearchDirty = true;
			}
		}

		private static float GetInvalidRemoveDelay()
		{
			if (Plugin.InvalidRemoveDelay == null)
			{
				return 30f;
			}
			return Mathf.Max(0f, Plugin.InvalidRemoveDelay.Value);
		}

		private static bool ShouldRemove(LobbyState state)
		{
			if (BlockedHostVisualEnabled(state))
			{
				return false;
			}
			if (state != null && state.Invalid && state.InvalidSince >= 0f)
			{
				return Time.unscaledTime - state.InvalidSince >= GetInvalidRemoveDelay();
			}
			return false;
		}

		private static string SafeLobbyName(Lobby lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return SafeGetData(lobby, "name") ?? "";
		}

		private static string SafeGetData(Lobby lobby, string key)
		{
			try
			{
				return ((Lobby)(ref lobby)).GetData(key) ?? "";
			}
			catch
			{
				return "";
			}
		}

		private static void ApplySnapshotToUi(SteamLobbyManager manager, Lobby[] snapshot)
		{
			//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_0067: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<ulong, LobbySlot> existingSlots = GetExistingSlots(manager);
			foreach (KeyValuePair<ulong, LobbySlot> item in existingSlots)
			{
				if (States.TryGetValue(item.Key, out var value))
				{
					UpdateSlot(item.Value, value);
				}
			}
			bool flag = true;
			for (int i = 0; i < snapshot.Length; i++)
			{
				Lobby val = snapshot[i];
				ulong num = SteamId.op_Implicit(((Lobby)(ref val)).Id);
				if (num != 0L && !existingSlots.ContainsKey(num) && flag && States.TryGetValue(num, out var value2) && (!value2.Removed || !value2.Invalid))
				{
					LobbySlot val2 = CreateSlot(manager, value2, existingSlots);
					if ((Object)(object)val2 != (Object)null)
					{
						existingSlots[num] = val2;
					}
				}
			}
			if (!((Object)(object)manager.serverListBlankText != (Object)null))
			{
				return;
			}
			int num2 = 0;
			foreach (KeyValuePair<ulong, LobbySlot> item2 in existingSlots)
			{
				LobbySlot value3 = item2.Value;
				if ((Object)(object)value3 != (Object)null && ((Component)value3).gameObject.activeInHierarchy)
				{
					num2++;
				}
			}
			string text = ((num2 == 0) ? "No servers have been found" : "");
			if (((TMP_Text)manager.serverListBlankText).text != text)
			{
				((TMP_Text)manager.serverListBlankText).text = text;
			}
		}

		private static bool IsLobbyReworkAppendedRow(Transform rowRoot)
		{
			if ((Object)(object)rowRoot != (Object)null && ((Object)((Component)rowRoot).gameObject).name != null)
			{
				return ((Object)((Component)rowRoot).gameObject).name.StartsWith("LobbyReworkAppended_", StringComparison.Ordinal);
			}
			return false;
		}

		private static ulong GetLobbyId(LobbySlot slot)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)slot == (Object)null)
			{
				return 0uL;
			}
			ulong num = SteamId.op_Implicit(((Lobby)(ref slot.thisLobby)).Id);
			if (num == 0L)
			{
				num = SteamId.op_Implicit(slot.lobbyId);
			}
			return num;
		}

		private static Transform GetLobbyRowRoot(LobbySlot slot, Transform container)
		{
			if ((Object)(object)slot == (Object)null)
			{
				return null;
			}
			Transform val = ((Component)slot).transform;
			if ((Object)(object)container == (Object)null)
			{
				return val;
			}
			while ((Object)(object)val.parent != (Object)null && (Object)(object)val.parent != (Object)(object)container)
			{
				val = val.parent;
			}
			return val;
		}

		private static RectTransform GetLobbyRowRect(LobbySlot slot, Transform container)
		{
			Transform lobbyRowRoot = GetLobbyRowRoot(slot, container);
			if (!((Object)(object)lobbyRowRoot == (Object)null))
			{
				return (RectTransform)(object)((lobbyRowRoot is RectTransform) ? lobbyRowRoot : null);
			}
			return null;
		}

		private static void DestroyLobbyRowRoot(LobbySlot slot, SteamLobbyManager manager)
		{
			if (!((Object)(object)slot == (Object)null) && !((Object)(object)manager == (Object)null) && !((Object)(object)manager.levelListContainer == (Object)null))
			{
				Transform lobbyRowRoot = GetLobbyRowRoot(slot, manager.levelListContainer);
				if (!((Object)(object)lobbyRowRoot == (Object)null))
				{
					((Component)lobbyRowRoot).gameObject.SetActive(false);
					Object.Destroy((Object)(object)((Component)lobbyRowRoot).gameObject);
				}
			}
		}

		private static Dictionary<ulong, LobbySlot> GetExistingSlots(SteamLobbyManager manager)
		{
			Dictionary<ulong, LobbySlot> existingSlotsScratch = ExistingSlotsScratch;
			existingSlotsScratch.Clear();
			if ((Object)(object)manager == (Object)null || (Object)(object)manager.levelListContainer == (Object)null)
			{
				return existingSlotsScratch;
			}
			int childCount = manager.levelListContainer.childCount;
			if (!uiScanRequested && childCount == cachedContainerChildCount)
			{
				foreach (KeyValuePair<ulong, LobbyState> state in States)
				{
					LobbyState value = state.Value;
					if (value != null && (Object)(object)value.Slot != (Object)null && !value.Removed)
					{
						existingSlotsScratch[state.Key] = value.Slot;
					}
				}
				if (existingSlotsScratch.Count > 0)
				{
					return existingSlotsScratch;
				}
			}
			existingSlotsScratch.Clear();
			List<LobbySlot> existingSlotsListScratch = ExistingSlotsListScratch;
			existingSlotsListScratch.Clear();
			((Component)manager.levelListContainer).GetComponentsInChildren<LobbySlot>(true, existingSlotsListScratch);
			bool flag = false;
			for (int i = 0; i < existingSlotsListScratch.Count; i++)
			{
				LobbySlot val = existingSlotsListScratch[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Transform lobbyRowRoot = GetLobbyRowRoot(val, manager.levelListContainer);
				if ((Object)(object)lobbyRowRoot == (Object)null)
				{
					continue;
				}
				ulong lobbyId = GetLobbyId(val);
				if (lobbyId == 0L)
				{
					continue;
				}
				LobbySlot value3;
				if (States.TryGetValue(lobbyId, out var value2) && value2.Removed && value2.Invalid)
				{
					DestroyLobbyRowRoot(val, manager);
					flag = true;
				}
				else if (existingSlotsScratch.TryGetValue(lobbyId, out value3))
				{
					Transform lobbyRowRoot2 = GetLobbyRowRoot(value3, manager.levelListContainer);
					if (!((Object)(object)lobbyRowRoot2 != (Object)(object)lobbyRowRoot))
					{
						continue;
					}
					bool flag2 = IsLobbyReworkAppendedRow(lobbyRowRoot2);
					bool flag3 = IsLobbyReworkAppendedRow(lobbyRowRoot);
					if (flag2 && !flag3)
					{
						DestroyLobbyRowRoot(value3, manager);
						existingSlotsScratch[lobbyId] = val;
						if (States.TryGetValue(lobbyId, out var value4))
						{
							AttachSlot(value4, val);
						}
						flag = true;
						if (Plugin.LoggingEnabled)
						{
							Plugin.LogInfo($"Replaced appended duplicate with vanilla row for {lobbyId}.");
						}
					}
					else if (!flag2 && flag3)
					{
						DestroyLobbyRowRoot(val, manager);
						flag = true;
						if (Plugin.LoggingEnabled)
						{
							Plugin.LogInfo($"Removed appended duplicate row for {lobbyId}.");
						}
					}
					else
					{
						DestroyLobbyRowRoot(val, manager);
						flag = true;
						if (Plugin.LoggingEnabled)
						{
							Plugin.LogInfo($"Removed same-owner duplicate row for {lobbyId}.");
						}
					}
				}
				else
				{
					existingSlotsScratch[lobbyId] = val;
					if (States.TryGetValue(lobbyId, out value2))
					{
						AttachSlot(value2, val);
					}
				}
			}
			if (flag)
			{
				cachedContainerChildCount = -1;
				uiScanRequested = true;
			}
			else
			{
				cachedContainerChildCount = manager.levelListContainer.childCount;
				uiScanRequested = false;
			}
			return existingSlotsScratch;
		}

		internal static bool HasActiveLocalNameSearch(SteamLobbyManager manager)
		{
			if ((Object)(object)manager != (Object)null && (Object)(object)manager.serverTagInputField != (Object)null)
			{
				return !string.IsNullOrWhiteSpace(manager.serverTagInputField.text);
			}
			return false;
		}

		private static bool HasActiveShowFilter()
		{
			if (selectedShowFilterMask == 0)
			{
				return hideSearchTags;
			}
			return true;
		}

		private static string GetSelectedShowFilter()
		{
			List<string> list = new List<string>();
			if ((selectedShowFilterMask & 1) != 0)
			{
				list.Add("Joinable");
			}
			if ((selectedShowFilterMask & 2) != 0)
			{
				list.Add("Friends");
			}
			if ((selectedShowFilterMask & 4) != 0)
			{
				list.Add("Blocked");
			}
			if ((selectedShowFilterMask & 8) != 0)
			{
				list.Add("Unjoinable");
			}
			if (list.Count == 0)
			{
				list.Add("All");
			}
			if (hideSearchTags)
			{
				list.Add("Hide tags");
			}
			return string.Join(", ", list.ToArray());
		}

		private static string GetShowDropdownCaption()
		{
			int num = 0;
			if ((selectedShowFilterMask & 1) != 0)
			{
				num++;
			}
			if ((selectedShowFilterMask & 2) != 0)
			{
				num++;
			}
			if ((selectedShowFilterMask & 4) != 0)
			{
				num++;
			}
			if ((selectedShowFilterMask & 8) != 0)
			{
				num++;
			}
			switch (num)
			{
			case 0:
				if (!hideSearchTags)
				{
					return "Show: All";
				}
				return "Show: All + Hide";
			case 1:
				if (!hideSearchTags)
				{
					if ((selectedShowFilterMask & 1) != 0)
					{
						return "Show: Joinable";
					}
					if ((selectedShowFilterMask & 2) != 0)
					{
						return "Show: Friends";
					}
					if ((selectedShowFilterMask & 4) != 0)
					{
						return "Show: Blocked";
					}
					return "Show: Unjoinable";
				}
				break;
			}
			int num2 = num + (hideSearchTags ? 1 : 0);
			return $"Show: {num2} selected";
		}

		private static bool IsShowMenuOptionSelected(int optionIndex)
		{
			return optionIndex switch
			{
				0 => selectedShowFilterMask == 0, 
				1 => (selectedShowFilterMask & 1) != 0, 
				2 => (selectedShowFilterMask & 2) != 0, 
				3 => (selectedShowFilterMask & 4) != 0, 
				4 => (selectedShowFilterMask & 8) != 0, 
				5 => hideSearchTags, 
				_ => false, 
			};
		}

		private static string GetShowMenuOptionLabel(int optionIndex)
		{
			if (optionIndex < 0 || optionIndex >= ShowFilterBaseLabels.Length)
			{
				return "";
			}
			return ShowFilterBaseLabels[optionIndex];
		}

		private static void ToggleShowMenuOption(int optionIndex)
		{
			switch (optionIndex)
			{
			case 0:
				selectedShowFilterMask = 0;
				break;
			case 1:
				if ((selectedShowFilterMask & 1) != 0)
				{
					selectedShowFilterMask &= -2;
					break;
				}
				selectedShowFilterMask &= -9;
				selectedShowFilterMask |= 1;
				break;
			case 2:
				selectedShowFilterMask ^= 2;
				break;
			case 3:
				selectedShowFilterMask ^= 4;
				break;
			case 4:
				if ((selectedShowFilterMask & 8) != 0)
				{
					selectedShowFilterMask &= -9;
					break;
				}
				selectedShowFilterMask &= -2;
				selectedShowFilterMask |= 8;
				break;
			case 5:
				hideSearchTags = !hideSearchTags;
				break;
			}
			RefreshShowDropdownVisuals();
			localSearchDirty = true;
			SteamLobbyManager val = cachedManager;
			if ((Object)(object)val != (Object)null)
			{
				ApplyLocalNameSearch(val, force: true);
			}
		}

		private static List<string> GetConfiguredSearchTags()
		{
			string text = ((Plugin.SearchTags == null) ? "" : (Plugin.SearchTags.Value ?? ""));
			if (string.Equals(text, cachedSearchTagsRaw, StringComparison.Ordinal))
			{
				return CachedSearchTags;
			}
			cachedSearchTagsRaw = text;
			CachedSearchTags.Clear();
			string[] array = text.Split(new char[4] { ',', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0)
				{
					continue;
				}
				bool flag = false;
				for (int j = 0; j < CachedSearchTags.Count; j++)
				{
					if (string.Equals(CachedSearchTags[j], text2, StringComparison.OrdinalIgnoreCase))
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					CachedSearchTags.Add(text2);
				}
			}
			return CachedSearchTags;
		}

		private static bool LobbyNameContainsHiddenTag(string lobbyName)
		{
			if (!hideSearchTags || string.IsNullOrEmpty(lobbyName))
			{
				return false;
			}
			List<string> configuredSearchTags = GetConfiguredSearchTags();
			for (int i = 0; i < configuredSearchTags.Count; i++)
			{
				if (lobbyName.IndexOf(configuredSearchTags[i], StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private static bool HasActiveLocalFilter(SteamLobbyManager manager)
		{
			if (!HasActiveLocalNameSearch(manager))
			{
				return HasActiveShowFilter();
			}
			return true;
		}

		internal static void NotifyLocalNameSearchChanged(SteamLobbyManager manager)
		{
			if ((Object)(object)manager != (Object)null)
			{
				cachedManager = manager;
			}
			localSearchDirty = true;
		}

		internal static void NotifySearchTagsChanged()
		{
			cachedSearchTagsRaw = null;
			CachedSearchTags.Clear();
			localSearchDirty = true;
			if ((Object)(object)cachedManager != (Object)null)
			{
				ApplyLocalNameSearch(cachedManager, force: true);
			}
		}

		private static bool StateMatchesLocalFilters(LobbyState state, string search)
		{
			if (state == null || state.Removed)
			{
				return false;
			}
			string text = state.Name ?? "";
			if (!string.IsNullOrWhiteSpace(search) && text.IndexOf(search, StringComparison.OrdinalIgnoreCase) < 0)
			{
				return false;
			}
			if (LobbyNameContainsHiddenTag(text))
			{
				return false;
			}
			if (selectedShowFilterMask == 0)
			{
				return true;
			}
			bool flag = false;
			if ((selectedShowFilterMask & 1) != 0)
			{
				flag |= !state.Invalid && !state.ProbeJoinRejected;
			}
			if ((selectedShowFilterMask & 2) != 0)
			{
				flag |= state.HostIsFriend || state.FriendsInLobby.Count > 0;
			}
			if ((selectedShowFilterMask & 4) != 0)
			{
				flag |= state.HostIsBlocked;
			}
			if ((selectedShowFilterMask & 8) != 0)
			{
				flag |= state.Invalid || state.ProbeJoinRejected;
			}
			return flag;
		}

		private static void ApplyLocalNameSearch(SteamLobbyManager manager, bool force = false)
		{
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)manager == (Object)null || (Object)(object)manager.levelListContainer == (Object)null)
			{
				return;
			}
			string text = (((Object)(object)manager.serverTagInputField == (Object)null) ? "" : (manager.serverTagInputField.text ?? "").Trim());
			int childCount = manager.levelListContainer.childCount;
			bool flag = !string.IsNullOrWhiteSpace(text) || HasActiveShowFilter();
			bool flag2 = lastAppliedNameSearch != text || lastAppliedShowFilterMask != selectedShowFilterMask || lastAppliedHideSearchTags != hideSearchTags;
			bool flag3 = emptyFilterCandidateSince >= 0f && (Object)(object)mana