Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LobbyRework v1.5.32
BepInEx/plugins/LobbyRework/LobbyRework.dll
Decompiled 9 hours ago
The result has been truncated due to the large size, download it to view full contents!
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