Decompiled source of BetterLoadingScreen v1.0.2

plugins/ZaboomafooW-BetterLoadingScreen-v1.0.2.dll

Decompiled a week 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 TMPro;
using Unity.Netcode;
using UnityEngine;

[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("ZaboomafooW-BetterLoadingScreen-v1.0.2")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyProduct("ZaboomafooW-BetterLoadingScreen-v1.0.2")]
[assembly: AssemblyTitle("ZaboomafooW-BetterLoadingScreen-v1.0.2")]
[assembly: AssemblyVersion("1.0.2.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 ZaboomafooW.BetterLoadingScreen
{
	internal sealed class LoadingScreenLifecycle : MonoBehaviour
	{
		private MenuManager menuManager;

		private TextMeshProUGUI initializedLoadingText;

		private float fixedWidth;

		private float fixedHeight;

		private bool initialized;

		internal void Initialize(MenuManager menuManager)
		{
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)menuManager == (Object)null || (Object)(object)menuManager.loadingScreen != (Object)(object)((Component)this).gameObject || (Object)(object)menuManager.loadingText == (Object)null || (initialized && (Object)(object)this.menuManager == (Object)(object)menuManager && (Object)(object)initializedLoadingText == (Object)(object)menuManager.loadingText))
			{
				return;
			}
			this.menuManager = menuManager;
			initializedLoadingText = menuManager.loadingText;
			RectTransform rectTransform = ((TMP_Text)initializedLoadingText).rectTransform;
			if ((Object)(object)rectTransform == (Object)null)
			{
				return;
			}
			string text = ((TMP_Text)initializedLoadingText).text;
			string text2 = LoadingStatusText.All[0];
			float num = 0f;
			for (int i = 0; i < LoadingStatusText.All.Length; i++)
			{
				((TMP_Text)initializedLoadingText).text = LoadingStatusText.All[i];
				((TMP_Text)initializedLoadingText).ForceMeshUpdate(true, false);
				float preferredWidth = ((TMP_Text)initializedLoadingText).preferredWidth;
				if (preferredWidth > num)
				{
					num = preferredWidth;
					text2 = LoadingStatusText.All[i];
				}
			}
			((TMP_Text)initializedLoadingText).text = text2 + "\n" + text2 + "\n" + text2;
			((TMP_Text)initializedLoadingText).ForceMeshUpdate(true, false);
			fixedWidth = ((TMP_Text)initializedLoadingText).preferredWidth;
			fixedHeight = ((TMP_Text)initializedLoadingText).preferredHeight;
			((TMP_Text)initializedLoadingText).text = text;
			((TMP_Text)initializedLoadingText).ForceMeshUpdate(true, false);
			if (!(fixedWidth <= 0f) && !(fixedHeight <= 0f))
			{
				Rect rect = rectTransform.rect;
				Vector3 val = ((Transform)rectTransform).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center));
				rectTransform.SetSizeWithCurrentAnchors((Axis)0, fixedWidth);
				rectTransform.SetSizeWithCurrentAnchors((Axis)1, fixedHeight);
				rect = rectTransform.rect;
				Vector3 val2 = ((Transform)rectTransform).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center));
				((Transform)rectTransform).position = ((Transform)rectTransform).position + (val - val2);
				initialized = true;
				if (((Component)this).gameObject.activeInHierarchy)
				{
					LoadingStatusController.OnLoadingScreenOpened(this.menuManager, fixedWidth, fixedHeight);
				}
			}
		}

		private void OnEnable()
		{
			if (initialized)
			{
				LoadingStatusController.OnLoadingScreenOpened(menuManager, fixedWidth, fixedHeight);
			}
		}

		private void OnDisable()
		{
			if (initialized)
			{
				LoadingStatusController.OnLoadingScreenClosed(initializedLoadingText);
			}
		}
	}
	internal static class LoadingStatusController
	{
		private static string currentStatus;

		private static string previousStatus;

		private static string oldestStatus;

		private static TextMeshProUGUI activeLoadingText;

		internal static void EnsureLoadingScreenInitialized(MenuManager menuManager)
		{
			if (!((Object)(object)menuManager == (Object)null) && !((Object)(object)menuManager.loadingScreen == (Object)null) && !((Object)(object)menuManager.loadingText == (Object)null))
			{
				LoadingScreenLifecycle loadingScreenLifecycle = menuManager.loadingScreen.GetComponent<LoadingScreenLifecycle>();
				if ((Object)(object)loadingScreenLifecycle == (Object)null)
				{
					loadingScreenLifecycle = menuManager.loadingScreen.AddComponent<LoadingScreenLifecycle>();
				}
				loadingScreenLifecycle.Initialize(menuManager);
			}
		}

		internal static void BeginServerLookup()
		{
			ReportStatus("Getting server information...");
		}

		internal static void BeginHosting(bool createsSteamLobby)
		{
			ReportStatus(createsSteamLobby ? "Creating lobby..." : "Starting server...");
		}

		internal static void RequestingLobbyAccess()
		{
			ReportStatus("Requesting lobby access...");
		}

		internal static void ContactingServer()
		{
			ReportStatus("Contacting server...");
		}

		internal static void WaitingForServerReply()
		{
			ReportStatus("Waiting for server reply...");
		}

		internal static void JoiningServer()
		{
			ReportStatus("Joining server...");
		}

		internal static void StartingServer()
		{
			ReportStatus("Starting server...");
		}

		internal static void LoadingGame()
		{
			ReportStatus("Loading game...");
		}

		internal static void OnLoadingScreenOpened(MenuManager menuManager, float fixedWidth, float fixedHeight)
		{
			if ((Object)(object)activeLoadingText != (Object)null)
			{
				((TMP_Text)activeLoadingText).OnPreRenderText -= ApplyVerticalAlphaGradient;
			}
			activeLoadingText = null;
			if ((Object)(object)menuManager == (Object)null || (Object)(object)menuManager.loadingText == (Object)null)
			{
				return;
			}
			activeLoadingText = menuManager.loadingText;
			RectTransform rectTransform = ((TMP_Text)activeLoadingText).rectTransform;
			if ((Object)(object)rectTransform == (Object)null)
			{
				activeLoadingText = null;
				return;
			}
			rectTransform.SetSizeWithCurrentAnchors((Axis)0, fixedWidth);
			rectTransform.SetSizeWithCurrentAnchors((Axis)1, fixedHeight);
			((TMP_Text)activeLoadingText).text = string.Empty;
			((TMP_Text)activeLoadingText).ForceMeshUpdate(true, false);
			((TMP_Text)activeLoadingText).OnPreRenderText -= ApplyVerticalAlphaGradient;
			((TMP_Text)activeLoadingText).OnPreRenderText += ApplyVerticalAlphaGradient;
			if (!string.IsNullOrWhiteSpace(currentStatus))
			{
				RenderStatusHistory();
			}
		}

		internal static void OnLoadingScreenClosed(TextMeshProUGUI loadingText)
		{
			if ((Object)(object)loadingText != (Object)null)
			{
				((TMP_Text)loadingText).OnPreRenderText -= ApplyVerticalAlphaGradient;
			}
			if (!((Object)(object)activeLoadingText != (Object)(object)loadingText))
			{
				activeLoadingText = null;
				ClearStatusHistory();
			}
		}

		internal static void ClearStatusHistory()
		{
			currentStatus = null;
			previousStatus = null;
			oldestStatus = null;
		}

		private static void ReportStatus(string status)
		{
			if (!string.IsNullOrWhiteSpace(status) && !string.Equals(currentStatus, status, StringComparison.Ordinal))
			{
				oldestStatus = previousStatus;
				previousStatus = currentStatus;
				currentStatus = status;
				if ((Object)(object)activeLoadingText != (Object)null)
				{
					RenderStatusHistory();
				}
			}
		}

		private static void RenderStatusHistory()
		{
			if (!((Object)(object)activeLoadingText == (Object)null) && !string.IsNullOrWhiteSpace(currentStatus))
			{
				string text = oldestStatus ?? string.Empty;
				string text2 = previousStatus ?? string.Empty;
				((TMP_Text)activeLoadingText).text = text + "\n" + text2 + "\n" + currentStatus;
				((TMP_Text)activeLoadingText).ForceMeshUpdate(true, false);
			}
		}

		private static void ApplyVerticalAlphaGradient(TMP_TextInfo textInfo)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			if (textInfo == null || textInfo.lineCount < 1)
			{
				return;
			}
			float ascender = textInfo.lineInfo[0].ascender;
			float descender = textInfo.lineInfo[textInfo.lineCount - 1].descender;
			float num = ascender - descender;
			if (num <= Mathf.Epsilon)
			{
				return;
			}
			for (int i = 0; i < textInfo.characterCount; i++)
			{
				TMP_CharacterInfo val = textInfo.characterInfo[i];
				if (val.isVisible)
				{
					TMP_MeshInfo val2 = textInfo.meshInfo[val.materialReferenceIndex];
					int vertexIndex = val.vertexIndex;
					for (int j = 0; j < 4; j++)
					{
						int num2 = vertexIndex + j;
						float num3 = Mathf.Clamp01((ascender - val2.vertices[num2].y) / num);
						Color32 val3 = val2.colors32[num2];
						val3.a = (byte)Mathf.RoundToInt((float)(int)val3.a * num3);
						val2.colors32[num2] = val3;
					}
				}
			}
		}
	}
	internal static class LoadingStatusText
	{
		internal const string GettingServerInformation = "Getting server information...";

		internal const string RequestingLobbyAccess = "Requesting lobby access...";

		internal const string ContactingServer = "Contacting server...";

		internal const string WaitingForServerReply = "Waiting for server reply...";

		internal const string JoiningServer = "Joining server...";

		internal const string StartingServer = "Starting server...";

		internal const string CreatingLobby = "Creating lobby...";

		internal const string LoadingGame = "Loading game...";

		internal static readonly string[] All = new string[8] { "Getting server information...", "Requesting lobby access...", "Contacting server...", "Waiting for server reply...", "Joining server...", "Starting server...", "Creating lobby...", "Loading game..." };
	}
	internal static class ConnectionStatusPatches
	{
		private const BindingFlags InstanceNonPublic = BindingFlags.Instance | BindingFlags.NonPublic;

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

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

		internal static bool Apply(Harmony harmony)
		{
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Expected O, but got Unknown
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Expected O, but got Unknown
			if (harmony == null)
			{
				Plugin.Log.LogError((object)"[BetterLoadingScreen] Could not hook connection status updates because the Harmony instance is null.");
				return false;
			}
			try
			{
				Assembly assembly = typeof(NetworkManager).Assembly;
				Type type = assembly.GetType("Unity.Netcode.NetworkConnectionManager", throwOnError: false);
				if (type == null)
				{
					Plugin.Log.LogError((object)"[BetterLoadingScreen] Could not find Unity.Netcode.NetworkConnectionManager.");
					return false;
				}
				Type type2 = assembly.GetType("Unity.Netcode.ConnectionApprovedMessage", throwOnError: false);
				if (type2 == null)
				{
					Plugin.Log.LogError((object)"[BetterLoadingScreen] Could not find Unity.Netcode.ConnectionApprovedMessage.");
					return false;
				}
				MethodInfo method = type.GetMethod("SendConnectionRequest", BindingFlags.Instance | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log.LogError((object)"[BetterLoadingScreen] Could not find NetworkConnectionManager.SendConnectionRequest.");
					return false;
				}
				MethodInfo method2 = type2.GetMethod("Handle", BindingFlags.Instance | BindingFlags.Public);
				if (method2 == null)
				{
					Plugin.Log.LogError((object)"[BetterLoadingScreen] Could not find ConnectionApprovedMessage.Handle.");
					return false;
				}
				MethodInfo method3 = typeof(ConnectionStatusPatches).GetMethod("ConnectionRequestPostfix", BindingFlags.Static | BindingFlags.NonPublic);
				if (method3 == null)
				{
					Plugin.Log.LogError((object)"[BetterLoadingScreen] Could not find ConnectionStatusPatches.ConnectionRequestPostfix.");
					return false;
				}
				MethodInfo method4 = typeof(ConnectionStatusPatches).GetMethod("ConnectionApprovedHandlePrefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (method4 == null)
				{
					Plugin.Log.LogError((object)"[BetterLoadingScreen] Could not find ConnectionStatusPatches.ConnectionApprovedHandlePrefix.");
					return false;
				}
				harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)method2, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[BetterLoadingScreen] Could not hook connection status updates: " + ex));
				return false;
			}
		}

		private static void ConnectionRequestPostfix()
		{
			LoadingStatusController.WaitingForServerReply();
		}

		private static void ConnectionApprovedHandlePrefix()
		{
			LoadingStatusController.JoiningServer();
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "StartClient")]
	internal static class GameNetworkManagerStartClientPatch
	{
		private static void Prefix()
		{
			LoadingStatusController.ContactingServer();
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "StartHost")]
	internal static class GameNetworkManagerStartHostPatch
	{
		private static void Prefix(GameNetworkManager __instance)
		{
			LoadingStatusController.BeginHosting(!__instance.disableSteam);
		}
	}
	[HarmonyPatch(typeof(LobbySlot), "JoinLobbyAfterVerifying")]
	internal static class JoinLobbyAfterVerifyingPatch
	{
		private static void Prefix()
		{
			LoadingStatusController.BeginServerLookup();
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "JoinLobby")]
	internal static class JoinLobbyPatch
	{
		private static void Prefix()
		{
			LoadingStatusController.RequestingLobbyAccess();
		}
	}
	[HarmonyPatch(typeof(MenuManager), "StartHosting")]
	internal static class MenuManagerStartHostingPatch
	{
		private static void Prefix()
		{
			LoadingStatusController.StartingServer();
		}
	}
	[HarmonyPatch(typeof(NetworkManager), "StartHost")]
	internal static class NetworkManagerStartHostPatch
	{
		private static void Postfix(bool __result)
		{
			if (__result)
			{
				LoadingStatusController.LoadingGame();
			}
		}
	}
	[HarmonyPatch(typeof(MenuManager), "SetLoadingScreen")]
	internal static class SetLoadingScreenPatch
	{
		private static void Prefix(MenuManager __instance)
		{
			LoadingStatusController.EnsureLoadingScreenInitialized(__instance);
		}

		private static void Postfix(bool isLoading)
		{
			if (!isLoading)
			{
				LoadingStatusController.ClearStatusHistory();
			}
		}
	}
	[BepInPlugin("ZaboomafooW.BetterLoadingScreen", "Better Loading Screen", "1.0.2")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "ZaboomafooW.BetterLoadingScreen";

		public const string PluginName = "Better Loading Screen";

		public const string PluginVersion = "1.0.2";

		private Harmony harmony;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"[BetterLoadingScreen] Loaded v1.0.2");
			harmony = new Harmony("ZaboomafooW.BetterLoadingScreen");
			try
			{
				harmony.PatchAll();
				if (!ConnectionStatusPatches.Apply(harmony))
				{
					harmony.UnpatchSelf();
					Log.LogError((object)"[BetterLoadingScreen] Could not hook connection status updates.");
					return;
				}
			}
			catch (Exception ex)
			{
				harmony.UnpatchSelf();
				Log.LogError((object)("[BetterLoadingScreen] Could not apply loading-screen hooks: " + ex));
				return;
			}
			Log.LogInfo((object)"[BetterLoadingScreen] Hooked join and host loading status updates.");
		}

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