Decompiled source of CancelJoiningLobby v1.0.5

ZaboomafooW-CancelJoiningLobby-v1.0.5.dll

Decompiled 2 weeks ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Logging;
using CancelJoiningLobby.Controllers;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using Steamworks.Data;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
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("CancelJoiningLobby")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.5.0")]
[assembly: AssemblyInformationalVersion("1.0.5")]
[assembly: AssemblyProduct("CancelJoiningLobby")]
[assembly: AssemblyTitle("CancelJoiningLobby")]
[assembly: AssemblyVersion("1.0.5.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 CancelJoiningLobby
{
	[BepInPlugin("ZaboomafooW.CancelJoiningLobby", "Cancel Joining Lobby", "1.0.5")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "ZaboomafooW.CancelJoiningLobby";

		public const string PluginName = "Cancel Joining Lobby";

		public const string PluginVersion = "1.0.5";

		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			if (ConnectionCancellationController.Initialize())
			{
				_harmony = new Harmony("ZaboomafooW.CancelJoiningLobby");
				_harmony.PatchAll();
				if (!ConnectionCancellationController.InstallConnectionLifecycleHooks(_harmony))
				{
					_harmony.UnpatchSelf();
					_harmony = null;
					ConnectionCancellationController.Cleanup();
				}
				else
				{
					Log.LogInfo((object)"[CancelJoiningLobby] Loaded v1.0.5");
				}
			}
		}

		private void OnApplicationQuit()
		{
			ConnectionCancellationController.Cleanup();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_harmony = null;
			Log = null;
		}
	}
}
namespace CancelJoiningLobby.Patches
{
	[HarmonyPatch(typeof(MenuManager), "DisplayMenuNotification")]
	internal static class DisplayMenuNotificationPatch
	{
		private static bool Prefix()
		{
			return !ConnectionCancellationController.ShouldSuppressMenuNotification;
		}
	}
	[HarmonyPatch(typeof(LobbySlot), "JoinLobbyAfterVerifying")]
	internal static class JoinLobbyAfterVerifyingPatch
	{
		private static void Prefix(Lobby lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			ConnectionCancellationController.CaptureJoinAttempt(lobby);
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "JoinLobby")]
	internal static class JoinLobbyPatch
	{
		[HarmonyPriority(0)]
		private static bool Prefix(GameNetworkManager __instance, Lobby lobby)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return !ConnectionCancellationController.InterceptSteamLobbyJoin(__instance, lobby);
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "OnPlayerConnectedClientRpc")]
	internal static class OnPlayerConnectedClientRpcPatch
	{
		[HarmonyPriority(800)]
		private static bool Prefix(StartOfRound __instance, ulong clientId)
		{
			return ConnectionCancellationController.ShouldRunLocalPlayerAssignment(__instance, clientId);
		}
	}
	[HarmonyPatch(typeof(MenuManager), "SetLoadingScreen")]
	internal static class SetLoadingScreenPatch
	{
		private static void Prefix(MenuManager __instance, out bool __state)
		{
			CancelButtonController.EnsureInitialized(__instance);
			__state = (Object)(object)__instance != (Object)null && (Object)(object)__instance.loadingScreen != (Object)null && __instance.loadingScreen.activeInHierarchy;
		}

		private static void Postfix(MenuManager __instance, bool isLoading, bool __state)
		{
			if (!(isLoading || __state))
			{
				ConnectionCancellationController.OnLoadingScreenClosed(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "StartClient")]
	internal static class StartClientPatch
	{
		private static void Prefix()
		{
			ConnectionCancellationController.BeginNetworkConnection();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "OnEnable")]
	internal static class StartOfRoundOnEnablePatch
	{
		[HarmonyPriority(800)]
		private static bool Prefix()
		{
			return ConnectionCancellationController.ShouldRunStartOfRoundOnEnable();
		}
	}
}
namespace CancelJoiningLobby.Controllers
{
	internal static class CancelButtonController
	{
		private const string ButtonObjectName = "CancelJoiningLobby.CancelButton";

		private const string ButtonText = "[ Cancel ]";

		private static GameObject _cancelButtonObject;

		private static RectTransform _cancelRectTransform;

		private static TextMeshProUGUI _cancelText;

		private static Image _hoverImage;

		private static CancelButtonInputHandler _inputHandler;

		private static CancelLoadingScreenLifecycleHandler _lifecycleHandler;

		private static float _verticalGap;

		private static GameObject _initializedOwner;

		private static MenuManager _initializedMenuManager;

		private static bool _hookSuccessLogged;

		internal static bool EnsureInitialized(MenuManager menuManager)
		{
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: 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_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)menuManager == (Object)null || (Object)(object)menuManager.loadingScreen == (Object)null || (Object)(object)menuManager.loadingText == (Object)null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] Loading screen UI was unavailable; Cancel could not be initialized.");
				return false;
			}
			if ((Object)(object)_initializedOwner == (Object)(object)menuManager.loadingScreen && (Object)(object)_cancelButtonObject != (Object)null && (Object)(object)_cancelRectTransform != (Object)null && (Object)(object)_cancelText != (Object)null && (Object)(object)_hoverImage != (Object)null && (Object)(object)_inputHandler != (Object)null && (Object)(object)_lifecycleHandler != (Object)null)
			{
				return true;
			}
			SetCancellationAvailable(available: false);
			ClearCachedReferences();
			RectTransform component = menuManager.loadingScreen.GetComponent<RectTransform>();
			Canvas componentInParent = menuManager.loadingScreen.GetComponentInParent<Canvas>();
			RectTransform rectTransform = ((TMP_Text)menuManager.loadingText).rectTransform;
			if ((Object)(object)component == (Object)null || (Object)(object)componentInParent == (Object)null || (Object)(object)rectTransform == (Object)null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] Loading screen layout was unavailable; Cancel could not be initialized.");
				return false;
			}
			GameObject val = new GameObject("CancelJoiningLobby.CancelButton", new Type[4]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(CancelButtonInputHandler)
			});
			val.transform.SetParent((Transform)(object)component, false);
			RectTransform component2 = val.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0.5f, 0.5f);
			component2.anchorMax = new Vector2(0.5f, 0.5f);
			component2.pivot = new Vector2(0.5f, 1f);
			Image component3 = val.GetComponent<Image>();
			((Graphic)component3).color = Color.clear;
			((Graphic)component3).raycastTarget = false;
			GameObject val2 = new GameObject("CancelJoiningLobby.CancelButton.Text", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(TextMeshProUGUI)
			});
			val2.transform.SetParent(val.transform, false);
			TextMeshProUGUI loadingText = menuManager.loadingText;
			TextMeshProUGUI component4 = val2.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component4).text = "[ Cancel ]";
			((TMP_Text)component4).font = ((TMP_Text)loadingText).font;
			((TMP_Text)component4).fontSharedMaterial = ((TMP_Text)loadingText).fontSharedMaterial;
			((TMP_Text)component4).fontSize = ((TMP_Text)loadingText).fontSize;
			((TMP_Text)component4).fontStyle = ((TMP_Text)loadingText).fontStyle;
			((Graphic)component4).color = ((Graphic)loadingText).color;
			((TMP_Text)component4).alignment = (TextAlignmentOptions)514;
			((TMP_Text)component4).enableWordWrapping = false;
			((Graphic)component4).raycastTarget = false;
			((TMP_Text)component4).ForceMeshUpdate(false, false);
			float preferredWidth = ((TMP_Text)component4).preferredWidth;
			float preferredHeight = ((TMP_Text)component4).preferredHeight;
			((TMP_Text)component4).text = "[ Cancel ]\n[ Cancel ]";
			((TMP_Text)component4).ForceMeshUpdate(false, false);
			float verticalGap = ((TMP_Text)component4).preferredHeight - preferredHeight;
			((TMP_Text)component4).text = "[ Cancel ]";
			((TMP_Text)component4).ForceMeshUpdate(false, false);
			component2.sizeDelta = new Vector2(preferredWidth, preferredHeight);
			RectTransform component5 = val2.GetComponent<RectTransform>();
			component5.anchorMin = Vector2.zero;
			component5.anchorMax = Vector2.one;
			component5.offsetMin = Vector2.zero;
			component5.offsetMax = Vector2.zero;
			CancelButtonInputHandler component6 = val.GetComponent<CancelButtonInputHandler>();
			component6.Initialize(component2, componentInParent, component3, component4, ((Graphic)loadingText).color);
			val.SetActive(false);
			_cancelButtonObject = val;
			_cancelRectTransform = component2;
			_cancelText = component4;
			_hoverImage = component3;
			_inputHandler = component6;
			_verticalGap = verticalGap;
			_initializedOwner = menuManager.loadingScreen;
			_initializedMenuManager = menuManager;
			CancelLoadingScreenLifecycleHandler cancelLoadingScreenLifecycleHandler = menuManager.loadingScreen.GetComponent<CancelLoadingScreenLifecycleHandler>();
			if ((Object)(object)cancelLoadingScreenLifecycleHandler == (Object)null)
			{
				cancelLoadingScreenLifecycleHandler = menuManager.loadingScreen.AddComponent<CancelLoadingScreenLifecycleHandler>();
			}
			_lifecycleHandler = cancelLoadingScreenLifecycleHandler;
			_lifecycleHandler.Initialize(menuManager);
			if (!_hookSuccessLogged)
			{
				_hookSuccessLogged = true;
				Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Hook succeeded: attached Cancel to the v81 loading screen.");
			}
			return true;
		}

		internal static bool IsInitializedOwner(MenuManager menuManager)
		{
			if ((Object)(object)menuManager != (Object)null && (Object)(object)menuManager.loadingScreen != (Object)null)
			{
				return (Object)(object)_initializedOwner == (Object)(object)menuManager.loadingScreen;
			}
			return false;
		}

		internal static void SetCancellationAvailable(bool available)
		{
			if ((Object)(object)_cancelButtonObject == (Object)null || (Object)(object)_inputHandler == (Object)null)
			{
				return;
			}
			if (available)
			{
				if (!PositionForActivation())
				{
					_inputHandler.SetCancellationAvailable(available: false);
					_cancelButtonObject.SetActive(false);
				}
				else
				{
					_cancelButtonObject.SetActive(true);
					_inputHandler.SetCancellationAvailable(available: true);
				}
			}
			else
			{
				_inputHandler.SetCancellationAvailable(available: false);
				_cancelButtonObject.SetActive(false);
			}
		}

		internal static void Cleanup()
		{
			SetCancellationAvailable(available: false);
			if ((Object)(object)_lifecycleHandler != (Object)null)
			{
				Object.Destroy((Object)(object)_lifecycleHandler);
			}
			if ((Object)(object)_cancelButtonObject != (Object)null)
			{
				Object.Destroy((Object)(object)_cancelButtonObject);
			}
			ClearCachedReferences();
			_hookSuccessLogged = false;
		}

		private static bool PositionForActivation()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_008f: 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_0099: 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)
			if ((Object)(object)_initializedOwner == (Object)null || !_initializedOwner.activeInHierarchy || (Object)(object)_initializedMenuManager == (Object)null || (Object)(object)_initializedMenuManager.loadingText == (Object)null || (Object)(object)_cancelRectTransform == (Object)null)
			{
				return false;
			}
			RectTransform rectTransform = ((TMP_Text)_initializedMenuManager.loadingText).rectTransform;
			if ((Object)(object)rectTransform == (Object)null)
			{
				return false;
			}
			Rect rect = rectTransform.rect;
			float x = ((Rect)(ref rect)).center.x;
			rect = rectTransform.rect;
			Vector3 position = ((Transform)rectTransform).TransformPoint(new Vector3(x, ((Rect)(ref rect)).yMin - _verticalGap, 0f));
			((Transform)_cancelRectTransform).position = position;
			return true;
		}

		private static void ClearCachedReferences()
		{
			_cancelButtonObject = null;
			_cancelRectTransform = null;
			_cancelText = null;
			_hoverImage = null;
			_inputHandler = null;
			_lifecycleHandler = null;
			_verticalGap = 0f;
			_initializedOwner = null;
			_initializedMenuManager = null;
		}
	}
	internal sealed class CancelButtonInputHandler : MonoBehaviour
	{
		private RectTransform _buttonRectTransform;

		private Canvas _loadingScreenCanvas;

		private Image _buttonBackground;

		private TextMeshProUGUI _buttonText;

		private Color _normalTextColor;

		private bool _isHighlighted;

		private InputAction _cancelAction;

		internal void Initialize(RectTransform buttonRectTransform, Canvas loadingScreenCanvas, Image buttonBackground, TextMeshProUGUI buttonText, Color normalTextColor)
		{
			//IL_001e: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			_buttonRectTransform = buttonRectTransform;
			_loadingScreenCanvas = loadingScreenCanvas;
			_buttonBackground = buttonBackground;
			_buttonText = buttonText;
			_normalTextColor = normalTextColor;
			_cancelAction = new InputAction("Cancel", (InputActionType)1, "<Keyboard>/escape", (string)null, (string)null, (string)null);
			_cancelAction.performed += OnCancelPerformed;
			SetHighlighted(highlighted: false);
		}

		internal void SetCancellationAvailable(bool available)
		{
			if (_cancelAction != null)
			{
				if (available)
				{
					_cancelAction.Enable();
					return;
				}
				_cancelAction.Disable();
				SetHighlighted(highlighted: false);
			}
		}

		private void Update()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_buttonRectTransform == (Object)null || (Object)(object)_loadingScreenCanvas == (Object)null || Mouse.current == null)
			{
				SetHighlighted(highlighted: false);
				return;
			}
			Vector2 val = ((InputControl<Vector2>)(object)((Pointer)Mouse.current).position).ReadValue();
			Camera val2 = (((int)_loadingScreenCanvas.renderMode == 0) ? null : _loadingScreenCanvas.worldCamera);
			bool flag = RectTransformUtility.RectangleContainsScreenPoint(_buttonRectTransform, val, val2);
			SetHighlighted(flag);
			if (flag && Mouse.current.leftButton.wasReleasedThisFrame)
			{
				Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Cancel clicked.");
				ConnectionCancellationController.CancelConnectionAttempt();
			}
		}

		private void OnDestroy()
		{
			if (_cancelAction != null)
			{
				_cancelAction.Disable();
				_cancelAction.performed -= OnCancelPerformed;
				_cancelAction.Dispose();
				_cancelAction = null;
			}
		}

		private void OnCancelPerformed(CallbackContext callbackContext)
		{
			Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Cancel requested with Escape.");
			ConnectionCancellationController.CancelConnectionAttempt();
		}

		private void SetHighlighted(bool highlighted)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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)
			if (!((Object)(object)_buttonBackground == (Object)null) && !((Object)(object)_buttonText == (Object)null) && _isHighlighted != highlighted)
			{
				_isHighlighted = highlighted;
				((Graphic)_buttonBackground).color = (highlighted ? _normalTextColor : Color.clear);
				((Graphic)_buttonText).color = (highlighted ? Color.black : _normalTextColor);
			}
		}
	}
	internal sealed class CancelLoadingScreenLifecycleHandler : MonoBehaviour
	{
		private MenuManager _menuManager;

		internal void Initialize(MenuManager menuManager)
		{
			_menuManager = menuManager;
		}

		private void OnEnable()
		{
			if (!((Object)(object)_menuManager == (Object)null))
			{
				ConnectionCancellationController.OnLoadingScreenOpened(_menuManager);
			}
		}

		private void OnDisable()
		{
			if (!((Object)(object)_menuManager == (Object)null))
			{
				ConnectionCancellationController.OnLoadingScreenClosed(_menuManager);
			}
		}
	}
	internal static class ConnectionCancellationController
	{
		private enum JoinStage
		{
			None,
			LobbyRefresh,
			SteamLobbyJoin,
			NetworkConnecting,
			JoiningServer
		}

		private const BindingFlags InstanceNonPublic = BindingFlags.Instance | BindingFlags.NonPublic;

		private const BindingFlags InstancePublic = BindingFlags.Instance | BindingFlags.Public;

		private const BindingFlags StaticNonPublic = BindingFlags.Static | BindingFlags.NonPublic;

		private static MethodInfo _setInstanceValuesBackToDefaultMethod;

		private static MethodInfo _startDisconnectMethod;

		private static MethodInfo _resetGameValuesToDefaultMethod;

		private static MethodInfo _currentLobbySetterMethod;

		private static FieldInfo _timeOutLobbyRefreshCoroutineField;

		private static NetworkManager _joinNetworkManager;

		private static NetworkManager _networkManagerAwaitingShutdown;

		private static MenuManager _joinMenuManager;

		private static GameObject _previousMenuSelection;

		private static Lobby? _activeJoinLobby;

		private static JoinStage _joinStage;

		private static int _nextJoinAttemptId;

		private static int _activeJoinAttemptId;

		private static bool _joinAttemptTracked;

		private static bool _cancellationInProgress;

		private static bool _postApprovalCancellation;

		private static bool _steamJoinOperationPending;

		private static bool _suppressMenuNotification;

		private static bool _originalMenuButtonsActive;

		private static bool _originalServerListActive;

		private static bool _originalLoadingScreenActive;

		private static float _originalMenuAudioVolume;

		private static bool _menuAudioStateCaptured;

		internal static bool ShouldSuppressMenuNotification => _suppressMenuNotification;

		private static void OnClientStopped(bool wasServer)
		{
			UnsubscribeClientStopped();
			ResetDisconnectReason();
			ReturnToCapturedMenu();
			Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Restored the previous menu after cancellation.");
			FinishCancellationToMenu();
		}

		private static void CompletePostApprovalCancellation()
		{
			if (_postApprovalCancellation)
			{
				GameNetworkManager instance = GameNetworkManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					Plugin.Log.LogError((object)"[CancelJoiningLobby] GameNetworkManager was unavailable after cancelling late in the join; could not return to MainMenu.");
					ClearJoinAttempt();
					_cancellationInProgress = false;
					_postApprovalCancellation = false;
				}
				else if (!ResetGameValuesToDefault(instance))
				{
					Plugin.Log.LogError((object)"[CancelJoiningLobby] Could not reset game state after cancelling late in the join.");
					ClearJoinAttempt();
					_cancellationInProgress = false;
					_postApprovalCancellation = false;
				}
				else
				{
					ResetDisconnectReason();
					CancelButtonController.SetCancellationAvailable(available: false);
					StopTrackingJoinNetwork();
					SceneManager.sceneLoaded -= OnMainMenuLoadedAfterCancellation;
					SceneManager.sceneLoaded += OnMainMenuLoadedAfterCancellation;
					SceneManager.LoadScene("MainMenu");
				}
			}
		}

		private static void OnMainMenuLoadedAfterCancellation(Scene scene, LoadSceneMode mode)
		{
			if (!string.Equals(((Scene)(ref scene)).name, "MainMenu", StringComparison.Ordinal))
			{
				return;
			}
			MenuManager val = Object.FindObjectOfType<MenuManager>();
			if ((Object)(object)val != (Object)null)
			{
				RestoreMainMenuState(val);
				if (_originalServerListActive)
				{
					RefreshServerList();
				}
			}
			else
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] MainMenu loaded without a MenuManager; the previous menu state could not be restored.");
			}
			ClearJoinAttempt();
			_cancellationInProgress = false;
			_postApprovalCancellation = false;
			SceneManager.sceneLoaded -= OnMainMenuLoadedAfterCancellation;
			Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Cancelled after server approval; restored the previous MainMenu state.");
		}

		private static void ReturnToCapturedMenu()
		{
			MenuManager joinMenuManager = _joinMenuManager;
			if ((Object)(object)joinMenuManager == (Object)null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] Saved menu state was unavailable after cancellation; could not restore the previous menu.");
				return;
			}
			_suppressMenuNotification = true;
			try
			{
				joinMenuManager.SetLoadingScreen(false, (RoomEnter)5, "");
			}
			finally
			{
				_suppressMenuNotification = false;
			}
			RestoreJoinMenuState(joinMenuManager);
			if (_originalServerListActive)
			{
				RefreshServerList();
			}
		}

		private static void RestoreJoinMenuState(MenuManager menuManager)
		{
			if ((Object)(object)menuManager.loadingScreen != (Object)null)
			{
				menuManager.loadingScreen.SetActive(_originalLoadingScreenActive);
			}
			if ((Object)(object)menuManager.menuButtons != (Object)null)
			{
				menuManager.menuButtons.SetActive(_originalMenuButtonsActive);
			}
			if ((Object)(object)menuManager.serverListUIContainer != (Object)null)
			{
				menuManager.serverListUIContainer.SetActive(_originalServerListActive);
			}
			if (_menuAudioStateCaptured && (Object)(object)menuManager.MenuAudio != (Object)null)
			{
				menuManager.MenuAudio.volume = _originalMenuAudioVolume;
			}
			if ((Object)(object)EventSystem.current != (Object)null && (Object)(object)_previousMenuSelection != (Object)null && _previousMenuSelection.activeInHierarchy)
			{
				EventSystem.current.SetSelectedGameObject(_previousMenuSelection);
			}
		}

		private static void RestoreMainMenuState(MenuManager menuManager)
		{
			if ((Object)(object)menuManager.menuButtons != (Object)null)
			{
				menuManager.menuButtons.SetActive(_originalMenuButtonsActive);
			}
			if ((Object)(object)menuManager.serverListUIContainer != (Object)null)
			{
				menuManager.serverListUIContainer.SetActive(_originalServerListActive);
			}
			if ((Object)(object)menuManager.loadingScreen != (Object)null)
			{
				menuManager.loadingScreen.SetActive(_originalLoadingScreenActive);
			}
			if (_menuAudioStateCaptured && (Object)(object)menuManager.MenuAudio != (Object)null)
			{
				menuManager.MenuAudio.volume = _originalMenuAudioVolume;
			}
		}

		private static void RefreshServerList()
		{
			SteamLobbyManager val = Object.FindObjectOfType<SteamLobbyManager>();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] Could not find the server list to refresh it after cancellation.");
				return;
			}
			val.LoadServerList();
			Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Refreshed the server list after cancellation.");
		}

		internal static bool Initialize()
		{
			try
			{
				_setInstanceValuesBackToDefaultMethod = typeof(GameNetworkManager).GetMethod("SetInstanceValuesBackToDefault", BindingFlags.Instance | BindingFlags.NonPublic);
				_startDisconnectMethod = typeof(GameNetworkManager).GetMethod("StartDisconnect", BindingFlags.Instance | BindingFlags.NonPublic);
				_resetGameValuesToDefaultMethod = typeof(GameNetworkManager).GetMethod("ResetGameValuesToDefault", BindingFlags.Instance | BindingFlags.NonPublic);
				_currentLobbySetterMethod = typeof(GameNetworkManager).GetProperty("currentLobby", BindingFlags.Instance | BindingFlags.Public)?.GetSetMethod(nonPublic: true);
				_timeOutLobbyRefreshCoroutineField = typeof(LobbySlot).GetField("timeOutLobbyRefreshCoroutine", BindingFlags.Static | BindingFlags.NonPublic);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[CancelJoiningLobby] Failed to find the Lethal Company join cleanup methods: " + ex));
				return false;
			}
			if (_setInstanceValuesBackToDefaultMethod == null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] GameNetworkManager.SetInstanceValuesBackToDefault was not found.");
				return false;
			}
			if (_startDisconnectMethod == null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] GameNetworkManager.StartDisconnect was not found.");
				return false;
			}
			if (_resetGameValuesToDefaultMethod == null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] GameNetworkManager.ResetGameValuesToDefault was not found.");
				return false;
			}
			if (_currentLobbySetterMethod == null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] GameNetworkManager.currentLobby setter was not found.");
				return false;
			}
			if (_timeOutLobbyRefreshCoroutineField == null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] LobbySlot.timeOutLobbyRefreshCoroutine was not found.");
				return false;
			}
			return true;
		}

		internal static bool InstallConnectionLifecycleHooks(Harmony harmony)
		{
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Expected O, but got Unknown
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Expected O, but got Unknown
			if (harmony == null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] Harmony was unavailable; connection hooks were not installed.");
				return false;
			}
			try
			{
				Type type = typeof(NetworkManager).Assembly.GetType("Unity.Netcode.ConnectionApprovedMessage", throwOnError: false);
				if (type == null)
				{
					Plugin.Log.LogError((object)"[CancelJoiningLobby] Unity.Netcode.ConnectionApprovedMessage was not found.");
					return false;
				}
				MethodInfo method = type.GetMethod("Handle", BindingFlags.Instance | BindingFlags.Public);
				MethodInfo method2 = typeof(ConnectionCancellationController).GetMethod("ConnectionApprovedHandlePrefix", BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo method3 = typeof(NetworkManager).GetMethod("ShutdownInternal", BindingFlags.Instance | BindingFlags.NonPublic);
				MethodInfo method4 = typeof(ConnectionCancellationController).GetMethod("NetworkManagerShutdownInternalPostfix", BindingFlags.Static | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log.LogError((object)"[CancelJoiningLobby] Unity.Netcode.ConnectionApprovedMessage.Handle was not found.");
					return false;
				}
				if (method2 == null)
				{
					Plugin.Log.LogError((object)"[CancelJoiningLobby] ConnectionCancellationController.ConnectionApprovedHandlePrefix was not found.");
					return false;
				}
				if (method3 == null)
				{
					Plugin.Log.LogError((object)"[CancelJoiningLobby] Unity.Netcode.NetworkManager.ShutdownInternal was not found.");
					return false;
				}
				if (method4 == null)
				{
					Plugin.Log.LogError((object)"[CancelJoiningLobby] ConnectionCancellationController.NetworkManagerShutdownInternalPostfix was not found.");
					return false;
				}
				harmony.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)method3, (HarmonyMethod)null, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[CancelJoiningLobby] Failed to install connection hooks: " + ex));
				return false;
			}
		}

		internal static void CaptureJoinAttempt(Lobby lobby)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (!_cancellationInProgress)
			{
				GameNetworkManager instance = GameNetworkManager.Instance;
				MenuManager menuManager = Object.FindObjectOfType<MenuManager>();
				if ((Object)(object)instance == (Object)null || !CanCaptureMenuState(menuManager))
				{
					ClearJoinAttempt();
					return;
				}
				ClearJoinAttempt();
				CaptureMenuState(menuManager);
				_activeJoinLobby = lobby;
				_activeJoinAttemptId = ++_nextJoinAttemptId;
				_joinAttemptTracked = true;
				_joinStage = JoinStage.LobbyRefresh;
			}
		}

		internal static void BeginNetworkConnection()
		{
			if (_cancellationInProgress)
			{
				return;
			}
			if (_joinAttemptTracked)
			{
				_joinStage = JoinStage.NetworkConnecting;
				_joinNetworkManager = NetworkManager.Singleton;
				return;
			}
			MenuManager menuManager = Object.FindObjectOfType<MenuManager>();
			if (CanCaptureMenuState(menuManager))
			{
				CaptureMenuState(menuManager);
				_activeJoinLobby = null;
				_activeJoinAttemptId = ++_nextJoinAttemptId;
				_joinAttemptTracked = true;
				_joinStage = JoinStage.NetworkConnecting;
				_joinNetworkManager = NetworkManager.Singleton;
			}
		}

		internal static void OnLoadingScreenOpened(MenuManager menuManager)
		{
			if (CancelButtonController.IsInitializedOwner(menuManager))
			{
				if (!_joinAttemptTracked || _cancellationInProgress)
				{
					CancelButtonController.SetCancellationAvailable(available: false);
				}
				else if (_joinStage != JoinStage.LobbyRefresh && _joinStage != JoinStage.SteamLobbyJoin && _joinStage != JoinStage.NetworkConnecting && _joinStage != JoinStage.JoiningServer)
				{
					CancelButtonController.SetCancellationAvailable(available: false);
				}
				else
				{
					CancelButtonController.SetCancellationAvailable(available: true);
				}
			}
		}

		internal static void OnLoadingScreenClosed(MenuManager menuManager)
		{
			if (CancelButtonController.IsInitializedOwner(menuManager))
			{
				CancelButtonController.SetCancellationAvailable(available: false);
				if (!_cancellationInProgress)
				{
					StopTrackingJoinNetwork();
					ClearTrackedJoinState();
				}
			}
		}

		internal static bool InterceptSteamLobbyJoin(GameNetworkManager gameNetworkManager, Lobby lobby)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			if (_joinAttemptTracked && !_cancellationInProgress && _joinStage == JoinStage.LobbyRefresh && _activeJoinLobby.HasValue)
			{
				Lobby value = _activeJoinLobby.Value;
				if (SteamId.op_Implicit(((Lobby)(ref value)).Id) == SteamId.op_Implicit(((Lobby)(ref lobby)).Id))
				{
					if (_steamJoinOperationPending)
					{
						Plugin.Log.LogWarning((object)"[CancelJoiningLobby] A previous Steam lobby request is still finishing. Returned to the previous menu without starting another join.");
						_cancellationInProgress = true;
						CancelButtonController.SetCancellationAvailable(available: false);
						ReturnToCapturedMenu();
						FinishCancellationToMenu();
						return true;
					}
					if (gameNetworkManager.currentLobby.HasValue)
					{
						ClearJoinAttempt();
						return false;
					}
					if (!SetCurrentLobby(gameNetworkManager, lobby))
					{
						Plugin.Log.LogError((object)"[CancelJoiningLobby] Could not set the current Steam lobby. Continuing with the normal game join without cancellation support.");
						ClearJoinAttempt();
						return false;
					}
					gameNetworkManager.steamLobbyName = ((Lobby)(ref lobby)).GetData("name");
					_joinStage = JoinStage.SteamLobbyJoin;
					_steamJoinOperationPending = true;
					int activeJoinAttemptId = _activeJoinAttemptId;
					JoinSteamLobbyAsync(gameNetworkManager, lobby, activeJoinAttemptId);
					return true;
				}
			}
			return false;
		}

		internal static void CancelConnectionAttempt()
		{
			if (_joinAttemptTracked && !_cancellationInProgress)
			{
				switch (_joinStage)
				{
				case JoinStage.LobbyRefresh:
					CancelLobbyRefresh();
					break;
				case JoinStage.SteamLobbyJoin:
					CancelSteamLobbyJoin();
					break;
				case JoinStage.NetworkConnecting:
					CancelNetworkConnectionBeforeApproval();
					break;
				case JoinStage.JoiningServer:
					CancelNetworkConnectionAfterApproval();
					break;
				}
			}
		}

		internal static void Cleanup()
		{
			UnsubscribeClientStopped();
			CancelButtonController.Cleanup();
			SceneManager.sceneLoaded -= OnMainMenuLoadedAfterCancellation;
			StopTrackingJoinNetwork();
			ClearTrackedJoinState();
			_setInstanceValuesBackToDefaultMethod = null;
			_startDisconnectMethod = null;
			_resetGameValuesToDefaultMethod = null;
			_currentLobbySetterMethod = null;
			_timeOutLobbyRefreshCoroutineField = null;
			_cancellationInProgress = false;
			_postApprovalCancellation = false;
			_steamJoinOperationPending = false;
			_suppressMenuNotification = false;
		}

		private static bool CanCaptureMenuState(MenuManager menuManager)
		{
			if ((Object)(object)menuManager != (Object)null && (Object)(object)menuManager.menuButtons != (Object)null && (Object)(object)menuManager.serverListUIContainer != (Object)null)
			{
				return (Object)(object)menuManager.loadingScreen != (Object)null;
			}
			return false;
		}

		private static void CaptureMenuState(MenuManager menuManager)
		{
			_joinMenuManager = menuManager;
			_originalMenuButtonsActive = menuManager.menuButtons.activeSelf;
			_originalServerListActive = menuManager.serverListUIContainer.activeSelf;
			_originalLoadingScreenActive = menuManager.loadingScreen.activeSelf;
			_menuAudioStateCaptured = (Object)(object)menuManager.MenuAudio != (Object)null;
			if (_menuAudioStateCaptured)
			{
				_originalMenuAudioVolume = menuManager.MenuAudio.volume;
			}
			_previousMenuSelection = (((Object)(object)EventSystem.current != (Object)null) ? EventSystem.current.currentSelectedGameObject : null);
		}

		private static bool StopLobbyRefreshTimeout(GameNetworkManager gameNetworkManager)
		{
			if (_timeOutLobbyRefreshCoroutineField == null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] LobbySlot.timeOutLobbyRefreshCoroutine is unavailable.");
				return false;
			}
			try
			{
				object? value = _timeOutLobbyRefreshCoroutineField.GetValue(null);
				Coroutine val = (Coroutine)((value is Coroutine) ? value : null);
				if (val != null)
				{
					((MonoBehaviour)gameNetworkManager).StopCoroutine(val);
					_timeOutLobbyRefreshCoroutineField.SetValue(null, null);
				}
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[CancelJoiningLobby] Failed to stop the lobby refresh timeout: " + ex));
				return false;
			}
		}

		private static bool SetCurrentLobby(GameNetworkManager gameNetworkManager, Lobby lobby)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (_currentLobbySetterMethod == null)
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] GameNetworkManager.currentLobby setter is unavailable.");
				return false;
			}
			try
			{
				_currentLobbySetterMethod.Invoke(gameNetworkManager, new object[1] { lobby });
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[CancelJoiningLobby] Failed to set the current Steam lobby: " + ex));
				return false;
			}
		}

		private static void ClearCurrentLobbyIfMatches(GameNetworkManager gameNetworkManager)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//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_0044: Unknown result type (might be due to invalid IL or missing references)
			if (_activeJoinLobby.HasValue && gameNetworkManager.currentLobby.HasValue)
			{
				Lobby value = gameNetworkManager.currentLobby.Value;
				ulong num = SteamId.op_Implicit(((Lobby)(ref value)).Id);
				value = _activeJoinLobby.Value;
				if (num == SteamId.op_Implicit(((Lobby)(ref value)).Id))
				{
					gameNetworkManager.SetCurrentLobbyNull();
					gameNetworkManager.steamIdsInLobby.Clear();
				}
			}
		}

		private static bool ResetGameNetworkManagerState(GameNetworkManager gameNetworkManager)
		{
			return InvokeGameNetworkManagerMethod(_setInstanceValuesBackToDefaultMethod, gameNetworkManager, "GameNetworkManager.SetInstanceValuesBackToDefault");
		}

		private static bool StartVanillaDisconnectCleanup(GameNetworkManager gameNetworkManager)
		{
			return InvokeGameNetworkManagerMethod(_startDisconnectMethod, gameNetworkManager, "GameNetworkManager.StartDisconnect");
		}

		private static bool ResetGameValuesToDefault(GameNetworkManager gameNetworkManager)
		{
			return InvokeGameNetworkManagerMethod(_resetGameValuesToDefaultMethod, gameNetworkManager, "GameNetworkManager.ResetGameValuesToDefault");
		}

		private static bool InvokeGameNetworkManagerMethod(MethodInfo gameNetworkManagerMethod, GameNetworkManager gameNetworkManager, string memberName)
		{
			if (gameNetworkManagerMethod == null)
			{
				Plugin.Log.LogError((object)("[CancelJoiningLobby] " + memberName + " is unavailable."));
				return false;
			}
			try
			{
				gameNetworkManagerMethod.Invoke(gameNetworkManager, null);
				return true;
			}
			catch (TargetInvocationException ex)
			{
				Exception? obj = ex.InnerException ?? ex;
				Plugin.Log.LogError((object)("[CancelJoiningLobby] " + memberName + " failed: " + obj));
				return false;
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)("[CancelJoiningLobby] " + memberName + " failed: " + ex2));
				return false;
			}
		}

		private static void SubscribeClientStopped(NetworkManager networkManager)
		{
			UnsubscribeClientStopped();
			_networkManagerAwaitingShutdown = networkManager;
			_networkManagerAwaitingShutdown.OnClientStopped += OnClientStopped;
		}

		private static void UnsubscribeClientStopped()
		{
			if (!((Object)(object)_networkManagerAwaitingShutdown == (Object)null))
			{
				_networkManagerAwaitingShutdown.OnClientStopped -= OnClientStopped;
				_networkManagerAwaitingShutdown = null;
			}
		}

		private static void StopTrackingJoinNetwork()
		{
			_joinNetworkManager = null;
		}

		private static bool IsActiveJoinAttempt(int joinAttemptId, Lobby lobby)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (_joinAttemptTracked && !_cancellationInProgress && _activeJoinAttemptId == joinAttemptId && _activeJoinLobby.HasValue)
			{
				Lobby value = _activeJoinLobby.Value;
				return SteamId.op_Implicit(((Lobby)(ref value)).Id) == SteamId.op_Implicit(((Lobby)(ref lobby)).Id);
			}
			return false;
		}

		private static void FinishCancellationToMenu()
		{
			ClearJoinAttempt();
			_cancellationInProgress = false;
		}

		private static void ClearJoinAttempt()
		{
			CancelButtonController.SetCancellationAvailable(available: false);
			StopTrackingJoinNetwork();
			ClearTrackedJoinState();
		}

		private static void ClearTrackedJoinState()
		{
			_joinAttemptTracked = false;
			_activeJoinAttemptId = 0;
			_activeJoinLobby = null;
			_joinStage = JoinStage.None;
			_joinMenuManager = null;
			_previousMenuSelection = null;
			_menuAudioStateCaptured = false;
			_originalMenuAudioVolume = 0f;
		}

		private static void ResetDisconnectReason()
		{
			GameNetworkManager instance = GameNetworkManager.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				instance.disconnectReason = 0;
				instance.disconnectionReasonMessage = string.Empty;
			}
		}

		internal static bool ShouldRunStartOfRoundOnEnable()
		{
			if (!_cancellationInProgress || !_postApprovalCancellation)
			{
				return true;
			}
			Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Skipped round callback setup while cancellation was shutting the client down.");
			return false;
		}

		internal static bool ShouldRunLocalPlayerAssignment(StartOfRound startOfRound, ulong clientId)
		{
			if (!_joinAttemptTracked || _joinStage != JoinStage.JoiningServer || (Object)(object)startOfRound == (Object)null)
			{
				return true;
			}
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || ((NetworkBehaviour)startOfRound).IsServer || ((NetworkBehaviour)startOfRound).IsHost || clientId != singleton.LocalClientId)
			{
				return true;
			}
			if (_cancellationInProgress)
			{
				Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Skipped local player assignment because cancellation was already in progress.");
				return false;
			}
			Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Local player assignment started; Cancel is now disabled.");
			ClearJoinAttempt();
			return true;
		}

		private static async Task JoinSteamLobbyAsync(GameNetworkManager gameNetworkManager, Lobby lobby, int joinAttemptId)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			RoomEnter val;
			try
			{
				val = await ((Lobby)(ref lobby)).Join();
			}
			catch (Exception ex)
			{
				_steamJoinOperationPending = false;
				Plugin.Log.LogError((object)("[CancelJoiningLobby] Steam lobby request failed: " + ex));
				if (IsActiveJoinAttempt(joinAttemptId, lobby))
				{
					gameNetworkManager.LeaveCurrentSteamLobby();
					gameNetworkManager.steamLobbyName = SteamClient.Name;
					MenuManager val2 = Object.FindObjectOfType<MenuManager>();
					if ((Object)(object)val2 != (Object)null)
					{
						val2.SetLoadingScreen(false, (RoomEnter)5, "The host has not loaded or has already landed their ship.");
					}
					else
					{
						ClearJoinAttempt();
					}
				}
				return;
			}
			_steamJoinOperationPending = false;
			if (!IsActiveJoinAttempt(joinAttemptId, lobby))
			{
				if ((int)val == 1)
				{
					try
					{
						((Lobby)(ref lobby)).Leave();
					}
					catch (Exception ex2)
					{
						Plugin.Log.LogError((object)("[CancelJoiningLobby] Failed to leave a Steam lobby that finished after cancellation: " + ex2));
					}
				}
			}
			else if ((Object)(object)gameNetworkManager == (Object)null)
			{
				ClearJoinAttempt();
			}
			else if ((int)val == 1)
			{
				gameNetworkManager.StartClient(((Lobby)(ref lobby)).Owner.Id);
			}
			else
			{
				gameNetworkManager.LeaveCurrentSteamLobby();
				gameNetworkManager.steamLobbyName = SteamClient.Name;
				MenuManager val3 = Object.FindObjectOfType<MenuManager>();
				if ((Object)(object)val3 != (Object)null)
				{
					val3.SetLoadingScreen(false, (RoomEnter)5, "The host has not loaded or has already landed their ship.");
				}
				else
				{
					ClearJoinAttempt();
				}
			}
		}

		private static void CancelLobbyRefresh()
		{
			_cancellationInProgress = true;
			CancelButtonController.SetCancellationAvailable(available: false);
			GameNetworkManager instance = GameNetworkManager.Instance;
			if ((Object)(object)instance == (Object)null || !StopLobbyRefreshTimeout(instance))
			{
				_cancellationInProgress = false;
				CancelButtonController.SetCancellationAvailable(available: true);
				Plugin.Log.LogError((object)"[CancelJoiningLobby] Could not cancel while getting server information because the lobby refresh timeout could not be stopped.");
			}
			else
			{
				instance.waitingForLobbyDataRefresh = false;
				SteamMatchmaking.OnLobbyDataChanged -= LobbySlot.OnLobbyDataRefresh;
				ReturnToCapturedMenu();
				Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Cancelled while getting server information; restored the previous menu.");
				FinishCancellationToMenu();
			}
		}

		private static void CancelSteamLobbyJoin()
		{
			_cancellationInProgress = true;
			CancelButtonController.SetCancellationAvailable(available: false);
			GameNetworkManager instance = GameNetworkManager.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				ClearCurrentLobbyIfMatches(instance);
				instance.steamLobbyName = SteamClient.Name;
			}
			ReturnToCapturedMenu();
			Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Cancelled while joining the Steam lobby. A late Steam success will be left without starting the game client.");
			FinishCancellationToMenu();
		}

		private static void CancelNetworkConnectionBeforeApproval()
		{
			GameNetworkManager instance = GameNetworkManager.Instance;
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)instance == (Object)null)
			{
				ClearJoinAttempt();
				return;
			}
			if (!ResetGameNetworkManagerState(instance))
			{
				Plugin.Log.LogError((object)"[CancelJoiningLobby] Could not cancel because the pending connection state could not be reset.");
				return;
			}
			_cancellationInProgress = true;
			CancelButtonController.SetCancellationAvailable(available: false);
			instance.localClientWaitingForApproval = false;
			instance.LeaveCurrentSteamLobby();
			instance.steamLobbyName = SteamClient.Name;
			StopTrackingJoinNetwork();
			if ((Object)(object)singleton == (Object)null || !singleton.IsClient || !singleton.IsListening)
			{
				ReturnToCapturedMenu();
				Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Cancelled before server approval; restored the previous menu.");
				FinishCancellationToMenu();
			}
			else
			{
				SubscribeClientStopped(singleton);
				singleton.Shutdown(true);
				Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Cancelled before server approval; waiting for Netcode to shut down.");
			}
		}

		private static void CancelNetworkConnectionAfterApproval()
		{
			GameNetworkManager instance = GameNetworkManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				ClearJoinAttempt();
				return;
			}
			_cancellationInProgress = true;
			_postApprovalCancellation = true;
			CancelButtonController.SetCancellationAvailable(available: false);
			instance.isDisconnecting = true;
			if (!StartVanillaDisconnectCleanup(instance))
			{
				instance.isDisconnecting = false;
				_cancellationInProgress = false;
				_postApprovalCancellation = false;
				CancelButtonController.SetCancellationAvailable(available: true);
				Plugin.Log.LogError((object)"[CancelJoiningLobby] Could not cancel during the final join step because disconnect cleanup failed.");
				return;
			}
			instance.localClientWaitingForApproval = false;
			StopTrackingJoinNetwork();
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)null && singleton.IsClient && singleton.IsListening)
			{
				UnsubscribeClientStopped();
				_networkManagerAwaitingShutdown = singleton;
				singleton.Shutdown(true);
				Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Cancelled during the final join step; waiting for Netcode to shut down.");
			}
			else
			{
				Plugin.Log.LogInfo((object)"[CancelJoiningLobby] Cancelled during the final join step after Netcode had already stopped.");
				CompletePostApprovalCancellation();
			}
		}

		private static void ConnectionApprovedHandlePrefix()
		{
			if (_joinAttemptTracked && !_cancellationInProgress && !((Object)(object)_joinNetworkManager == (Object)null) && !((Object)(object)NetworkManager.Singleton != (Object)(object)_joinNetworkManager) && _joinStage == JoinStage.NetworkConnecting)
			{
				_joinStage = JoinStage.JoiningServer;
			}
		}

		private static void NetworkManagerShutdownInternalPostfix(NetworkManager __instance)
		{
			if (_cancellationInProgress && _postApprovalCancellation && !((Object)(object)__instance == (Object)null) && !((Object)(object)_networkManagerAwaitingShutdown != (Object)(object)__instance))
			{
				_networkManagerAwaitingShutdown = null;
				CompletePostApprovalCancellation();
			}
		}
	}
}