Decompiled source of BetterDisconnectReasons v1.0.1

BepInEx/plugins/ZaboomafooW-BetterDisconnectReasons-v1.0.1.dll

Decompiled an hour ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Netcode.Transports.Facepunch;
using Steamworks;
using Steamworks.Data;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BetterDisconnectReasons")]
[assembly: AssemblyDescription("Clearer client-side disconnect messages for Lethal Company v81")]
[assembly: AssemblyCompany("ZaboomafooW")]
[assembly: AssemblyProduct("BetterDisconnectReasons")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("1.0.1.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 BetterDisconnectReasons
{
	internal static class ReconnectController
	{
		internal static ulong SavedHostSteamId { get; private set; }

		internal static Lobby SavedLobby { get; private set; }

		internal static bool HasSavedLobby { get; private set; }

		internal static bool PendingReconnect { get; private set; }

		internal static bool ReconnectInProgress { get; private set; }

		internal static ConnectionState OriginalDisconnectState { get; private set; }

		internal static NetConnectionEnd OriginalDisconnectEndReason { get; private set; }

		private static bool HasOriginalDisconnectInfo { get; set; }

		internal static void RecordServer(SteamId hostSteamId, GameNetworkManager gameNetworkManager)
		{
			//IL_0000: 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)
			SavedHostSteamId = SteamId.op_Implicit(hostSteamId);
			if (!ReconnectInProgress)
			{
				ClearOriginalDisconnectInfo();
			}
			if ((Object)(object)gameNetworkManager != (Object)null && gameNetworkManager.currentLobby.HasValue)
			{
				SavedLobby = gameNetworkManager.currentLobby.Value;
				HasSavedLobby = true;
			}
			else if (!ReconnectInProgress)
			{
				HasSavedLobby = false;
			}
		}

		internal static void RecordSteamDisconnect(ConnectionInfo info)
		{
			//IL_0038: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (!ReconnectInProgress && !PendingReconnect && !HasOriginalDisconnectInfo)
			{
				GameNetworkManager instance = GameNetworkManager.Instance;
				if (!((Object)(object)instance == (Object)null) && !instance.isDisconnecting && !instance.localClientWaitingForApproval)
				{
					OriginalDisconnectState = ((ConnectionInfo)(ref info)).State;
					OriginalDisconnectEndReason = ((ConnectionInfo)(ref info)).EndReason;
					HasOriginalDisconnectInfo = true;
					Plugin.Log.LogInfo((object)$"[BetterDisconnectReasons] Saved Steam disconnect: state={OriginalDisconnectState}, endReason={OriginalDisconnectEndReason}.");
				}
			}
		}

		internal static void RecordUnexpectedDisconnect(GameNetworkManager gameNetworkManager)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (SavedHostSteamId == 0L)
			{
				Plugin.Log.LogWarning((object)"[BetterDisconnectReasons] Unexpected disconnect, but no host Steam ID was saved. Using vanilla handling.");
				return;
			}
			if ((Object)(object)gameNetworkManager != (Object)null && gameNetworkManager.currentLobby.HasValue)
			{
				SavedLobby = gameNetworkManager.currentLobby.Value;
				HasSavedLobby = true;
			}
			PendingReconnect = true;
			ReconnectInProgress = false;
			Plugin.Log.LogInfo((object)$"[BetterDisconnectReasons] Unexpected disconnect. Reconnecting to host {SavedHostSteamId}.");
		}

		internal static void MarkLobbyClosedForRound()
		{
			HasSavedLobby = false;
		}

		internal static void BeginReconnect()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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 (PendingReconnect && !ReconnectInProgress && SavedHostSteamId != 0L)
			{
				PendingReconnect = false;
				ReconnectInProgress = true;
				Plugin.Log.LogInfo((object)"[BetterDisconnectReasons] Starting reconnect.");
				GameNetworkManager instance = GameNetworkManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					FailReconnect("Server no longer exists.");
				}
				else if (HasSavedLobby)
				{
					instance.JoinLobby(SavedLobby, SteamId.op_Implicit(SavedHostSteamId));
				}
				else
				{
					instance.StartClient(SteamId.op_Implicit(SavedHostSteamId));
				}
			}
		}

		internal static SteamId ResolveReconnectTarget(SteamId requestedTarget)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!ReconnectInProgress || SavedHostSteamId == 0L)
			{
				return requestedTarget;
			}
			return SteamId.op_Implicit(SavedHostSteamId);
		}

		internal static void CompleteSuccessfulReconnect()
		{
			if (ReconnectInProgress)
			{
				ReconnectInProgress = false;
				ClearOriginalDisconnectInfo();
				Plugin.Log.LogInfo((object)"[BetterDisconnectReasons] Reconnect accepted.");
			}
		}

		internal static string NormalizeDisconnectionReason(string reason)
		{
			if (string.IsNullOrEmpty(reason))
			{
				return reason;
			}
			switch (reason)
			{
			case "You cannot rejoin after being kicked.":
				return "You were kicked.";
			case "Game has already started!":
				if (OriginalDisconnectWasClosedByPeer())
				{
					return "You were kicked.";
				}
				if (OriginalDisconnectWasConnectionFailure())
				{
					return "You disconnected. The game has already started.";
				}
				return reason;
			case "Lobby is full!":
				if (OriginalDisconnectWasClosedByPeer())
				{
					return "You were kicked.";
				}
				if (OriginalDisconnectWasConnectionFailure())
				{
					return "You disconnected. The server is now full.";
				}
				return "Server is full.";
			case "The host was not accepting connections.":
				return "Server no longer exists.";
			case "Unknown; please verify your game files.":
				return "Connection approval request was invalid.";
			default:
				return reason;
			}
		}

		internal static void CompleteFailedReconnect(string displayedReason)
		{
			if (ReconnectInProgress)
			{
				ReconnectInProgress = false;
				Plugin.Log.LogInfo((object)("[BetterDisconnectReasons] Reconnect failed: " + displayedReason));
			}
		}

		internal static void FailReconnect(string reason)
		{
			ReconnectInProgress = false;
			PendingReconnect = false;
			if ((Object)(object)GameNetworkManager.Instance != (Object)null)
			{
				GameNetworkManager.Instance.disconnectionReasonMessage = reason;
			}
			Plugin.Log.LogInfo((object)("[BetterDisconnectReasons] Could not reconnect: " + reason));
		}

		internal static void ResetAll()
		{
			//IL_0009: 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)
			SavedHostSteamId = 0uL;
			SavedLobby = default(Lobby);
			HasSavedLobby = false;
			PendingReconnect = false;
			ReconnectInProgress = false;
			ClearOriginalDisconnectInfo();
		}

		private static bool OriginalDisconnectWasClosedByPeer()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			return (int)OriginalDisconnectState == 4;
		}

		private static bool OriginalDisconnectWasConnectionFailure()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected I4, but got Unknown
			if ((int)OriginalDisconnectState == 5)
			{
				return true;
			}
			int num = (int)OriginalDisconnectEndReason;
			if (num >= 3000)
			{
				return num <= 5999;
			}
			return false;
		}

		private static void ClearOriginalDisconnectInfo()
		{
			OriginalDisconnectState = (ConnectionState)0;
			OriginalDisconnectEndReason = (NetConnectionEnd)0;
			HasOriginalDisconnectInfo = false;
		}
	}
	[HarmonyPatch]
	internal static class GameNetworkManagerPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(GameNetworkManager), "StartClient")]
		private static void StartClientPrefix(GameNetworkManager __instance, ref SteamId id)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			id = ReconnectController.ResolveReconnectTarget(id);
			ReconnectController.RecordServer(id, __instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GameNetworkManager), "Singleton_OnClientDisconnectCallback")]
		private static void ClientDisconnectPrefix(GameNetworkManager __instance, ulong clientId)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (!((Object)(object)singleton == (Object)null) && !((Object)(object)__instance == (Object)null) && !ReconnectController.ReconnectInProgress && !ReconnectController.PendingReconnect && !__instance.isDisconnecting && !__instance.localClientWaitingForApproval && !singleton.IsServer && singleton.IsClient && (clientId == 0L || clientId == singleton.LocalClientId))
			{
				ReconnectController.RecordUnexpectedDisconnect(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameNetworkManager), "Singleton_OnClientConnectedCallback")]
		private static void ClientConnectedPostfix(ulong clientId)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (!((Object)(object)singleton == (Object)null) && ReconnectController.ReconnectInProgress && clientId == singleton.LocalClientId)
			{
				ReconnectController.CompleteSuccessfulReconnect();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameNetworkManager), "LeaveLobbyAtGameStart")]
		private static void LeaveLobbyAtGameStartPostfix()
		{
			ReconnectController.MarkLobbyClosedForRound();
		}
	}
	[HarmonyPatch]
	internal static class MenuManagerPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(MenuManager), "Start")]
		private static void StartPrefix()
		{
			if (ReconnectController.PendingReconnect && !((Object)(object)GameNetworkManager.Instance == (Object)null))
			{
				GameNetworkManager.Instance.disconnectReason = 0;
				GameNetworkManager.Instance.disconnectionReasonMessage = string.Empty;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MenuManager), "Start")]
		private static void StartPostfix(MenuManager __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && ReconnectController.PendingReconnect)
			{
				ReconnectController.BeginReconnect();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MenuManager), "SetLoadingScreen")]
		private static void SetLoadingScreenPrefix(bool isLoading, ref RoomEnter result, ref string overrideMessage)
		{
			if (!isLoading && ReconnectController.ReconnectInProgress)
			{
				GameNetworkManager instance = GameNetworkManager.Instance;
				if ((Object)(object)instance != (Object)null && !string.IsNullOrEmpty(instance.disconnectionReasonMessage))
				{
					instance.disconnectionReasonMessage = ReconnectController.NormalizeDisconnectionReason(instance.disconnectionReasonMessage);
				}
				else if (!string.IsNullOrEmpty(overrideMessage))
				{
					overrideMessage = "Server no longer exists.";
				}
				else if ((int)result == 5 || (int)result == 2)
				{
					overrideMessage = "Server no longer exists.";
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MenuManager), "SetLoadingScreen")]
		private static void SetLoadingScreenPostfix(bool isLoading, string overrideMessage)
		{
			if (!isLoading && ReconnectController.ReconnectInProgress)
			{
				string text = overrideMessage;
				if (string.IsNullOrEmpty(text) && (Object)(object)GameNetworkManager.Instance != (Object)null)
				{
					text = GameNetworkManager.Instance.disconnectionReasonMessage;
				}
				if (string.IsNullOrEmpty(text))
				{
					text = "Server no longer exists.";
				}
				ReconnectController.CompleteFailedReconnect(text);
			}
		}
	}
	[HarmonyPatch(typeof(ConnectionManager), "OnDisconnected")]
	internal static class SteamConnectionPatches
	{
		[HarmonyPrefix]
		private static void OnDisconnectedPrefix(ConnectionManager __instance, ConnectionInfo info)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (__instance != null && __instance.Interface is FacepunchTransport)
			{
				ReconnectController.RecordSteamDisconnect(info);
			}
		}
	}
	[BepInPlugin("ZaboomafooW.BetterDisconnectReasons", "BetterDisconnectReasons", "1.0.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "ZaboomafooW.BetterDisconnectReasons";

		public const string PluginName = "BetterDisconnectReasons";

		public const string PluginVersion = "1.0.1";

		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("ZaboomafooW.BetterDisconnectReasons");
			_harmony.PatchAll();
			Log.LogInfo((object)"[BetterDisconnectReasons] Loaded v1.0.1");
			Log.LogInfo((object)"[BetterDisconnectReasons] Hook succeeded: disconnect/reconnect patches applied.");
		}

		private void OnApplicationQuit()
		{
			ReconnectController.ResetAll();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Log = null;
		}
	}
}