Decompiled source of BetterServerScrolling v1.0.0

BepInEx/plugins/BetterServerScrolling/ZaboomafooW-BetterServerScrolling-v1.0.0.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using BetterServerScrolling.Controllers;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
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("ZaboomafooW-BetterServerScrolling-v1.0.0")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ZaboomafooW-BetterServerScrolling-v1.0.0")]
[assembly: AssemblyTitle("ZaboomafooW-BetterServerScrolling-v1.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 BetterServerScrolling
{
	[BepInPlugin("ZaboomafooW.BetterServerScrolling", "BetterServerScrolling", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal const string PluginGuid = "ZaboomafooW.BetterServerScrolling";

		internal const string PluginName = "BetterServerScrolling";

		internal const string PluginVersion = "1.0.0";

		private Harmony? harmonyInstance;

		internal static ManualLogSource LogSource { 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
			LogSource = ((BaseUnityPlugin)this).Logger;
			harmonyInstance = new Harmony("ZaboomafooW.BetterServerScrolling");
			harmonyInstance.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[BetterServerScrolling] Loaded v1.0.0");
		}

		private void OnApplicationQuit()
		{
			if (harmonyInstance != null)
			{
				harmonyInstance.UnpatchSelf();
				harmonyInstance = null;
			}
		}
	}
}
namespace BetterServerScrolling.Patches
{
	[HarmonyPatch]
	internal static class ServerListScrollPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(ScrollRect), "OnScroll")]
		private static void ScrollRectOnScrollPrefix(ScrollRect __instance, PointerEventData eventData)
		{
			ServerListScrollController.NormalizeServerListScrollInput(__instance, eventData);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(SteamLobbyManager), "LoadServerList")]
		private static void LoadServerListPrefix(SteamLobbyManager __instance)
		{
			ServerListScrollController.PrepareServerListForRefresh(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SteamLobbyManager), "loadLobbyListAndFilter")]
		private static void LoadLobbyListAndFilterPostfix(SteamLobbyManager __instance, ref IEnumerator __result)
		{
			if (__result != null)
			{
				__result = ServerListScrollController.WrapServerListPopulation(__instance, __result);
			}
		}
	}
}
namespace BetterServerScrolling.Controllers
{
	internal static class ServerListScrollController
	{
		private readonly struct ServerRowPositionSnapshot
		{
			internal RectTransform RowRectTransform { get; }

			internal Vector3 WorldPosition { get; }

			internal ServerRowPositionSnapshot(RectTransform rowRectTransform, Vector3 worldPosition)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				RowRectTransform = rowRectTransform;
				WorldPosition = worldPosition;
			}
		}

		private const float ServerRowSpacing = 42f;

		private const float ServerRowScrollSensitivity = 42f;

		private const float ServerRowPositionTolerance = 0.25f;

		private const float ScrollOverflowTolerance = 0.5f;

		private const float ServerRowsPerWheelStep = 1.5f;

		private static bool serverListHookLogged;

		private static ScrollRect? activeServerListScrollRect;

		private static int lastAppliedVisibleServerCount = -1;

		private static bool lastAppliedScrollingEnabled;

		private static int lastLoggedVisibleServerCount = -1;

		private static bool? lastLoggedScrollingEnabled;

		internal static void PrepareServerListForRefresh(SteamLobbyManager steamLobbyManager)
		{
			//IL_0036: 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)
			lastAppliedVisibleServerCount = -1;
			if (TryGetServerListScrollContext(steamLobbyManager, out RectTransform serverListContent, out ScrollRect serverListScrollRect, out RectTransform serverListViewport))
			{
				serverListScrollRect.StopMovement();
				serverListScrollRect.movementType = (MovementType)2;
				serverListScrollRect.scrollSensitivity = 42f;
				serverListScrollRect.verticalScrollbarVisibility = (ScrollbarVisibility)1;
				RectTransform serverListContent2 = serverListContent;
				Rect rect = serverListViewport.rect;
				ResizeServerListContentPreservingTop(serverListContent2, ((Rect)(ref rect)).height, null);
				serverListScrollRect.verticalNormalizedPosition = 1f;
				serverListScrollRect.vertical = false;
				Canvas.ForceUpdateCanvases();
			}
		}

		internal static IEnumerator WrapServerListPopulation(SteamLobbyManager steamLobbyManager, IEnumerator vanillaPopulationCoroutine)
		{
			while (vanillaPopulationCoroutine.MoveNext())
			{
				ApplyCurrentServerListLayout(steamLobbyManager, populationFinished: false);
				yield return vanillaPopulationCoroutine.Current;
			}
			ApplyCurrentServerListLayout(steamLobbyManager, populationFinished: true);
		}

		internal static void NormalizeServerListScrollInput(ScrollRect scrollRect, PointerEventData eventData)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)scrollRect == (Object)null) && eventData != null && !((Object)(object)scrollRect != (Object)(object)activeServerListScrollRect) && scrollRect.vertical)
			{
				Vector2 scrollDelta = eventData.scrollDelta;
				scrollDelta.x = Mathf.Clamp(scrollDelta.x, -1f, 1f);
				scrollDelta.y = Mathf.Clamp(scrollDelta.y, -1f, 1f) * 1.5f;
				eventData.scrollDelta = scrollDelta;
			}
		}

		private static void ApplyCurrentServerListLayout(SteamLobbyManager steamLobbyManager, bool populationFinished)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetServerListScrollContext(steamLobbyManager, out RectTransform serverListContent, out ScrollRect serverListScrollRect, out RectTransform serverListViewport) || !TryGetVisibleServerCount(steamLobbyManager, out var visibleServerCount))
			{
				return;
			}
			if (visibleServerCount != lastAppliedVisibleServerCount)
			{
				Rect rect = serverListViewport.rect;
				float height = ((Rect)(ref rect)).height;
				if (height <= 0f)
				{
					Plugin.LogSource.LogWarning((object)"[BetterServerScrolling] Server list viewport height was not valid; leaving vanilla bounds unchanged.");
					return;
				}
				List<ServerRowPositionSnapshot> serverRowPositions = new List<ServerRowPositionSnapshot>();
				float requiredContentHeight = 0f;
				if (visibleServerCount > 0 && !TryMeasureVisibleServerRows(serverListContent, visibleServerCount, serverRowPositions, out requiredContentHeight))
				{
					Plugin.LogSource.LogWarning((object)string.Format("[{0}] Could not verify all {1} populated server rows; leaving vanilla bounds unchanged.", "BetterServerScrolling", visibleServerCount));
					return;
				}
				float targetContentHeight = Mathf.Max(height, requiredContentHeight);
				bool vertical = requiredContentHeight > height + 0.5f;
				serverListScrollRect.StopMovement();
				serverListScrollRect.movementType = (MovementType)2;
				serverListScrollRect.scrollSensitivity = 42f;
				serverListScrollRect.verticalScrollbarVisibility = (ScrollbarVisibility)1;
				ResizeServerListContentPreservingTop(serverListContent, targetContentHeight, serverRowPositions);
				serverListScrollRect.vertical = vertical;
				Canvas.ForceUpdateCanvases();
				lastAppliedVisibleServerCount = visibleServerCount;
				lastAppliedScrollingEnabled = vertical;
			}
			if (populationFinished && (lastLoggedVisibleServerCount != visibleServerCount || lastLoggedScrollingEnabled != lastAppliedScrollingEnabled))
			{
				string arg = (lastAppliedScrollingEnabled ? "enabled" : "disabled");
				Plugin.LogSource.LogInfo((object)string.Format("[{0}] Corrected server list bounds for {1} visible servers; scrolling {2}.", "BetterServerScrolling", visibleServerCount, arg));
				lastLoggedVisibleServerCount = visibleServerCount;
				lastLoggedScrollingEnabled = lastAppliedScrollingEnabled;
			}
		}

		private static bool TryGetServerListScrollContext(SteamLobbyManager steamLobbyManager, out RectTransform serverListContent, out ScrollRect serverListScrollRect, out RectTransform serverListViewport)
		{
			//IL_009d: 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)
			serverListContent = null;
			serverListScrollRect = null;
			serverListViewport = null;
			if ((Object)(object)steamLobbyManager == (Object)null || (Object)(object)steamLobbyManager.levelListContainer == (Object)null)
			{
				return false;
			}
			Transform levelListContainer = steamLobbyManager.levelListContainer;
			RectTransform val = (RectTransform)(object)((levelListContainer is RectTransform) ? levelListContainer : null);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.LogSource.LogWarning((object)"[BetterServerScrolling] levelListContainer was not a RectTransform; leaving the server list unchanged.");
				return false;
			}
			ScrollRect componentInParent = ((Component)val).GetComponentInParent<ScrollRect>();
			if ((Object)(object)componentInParent == (Object)null || (Object)(object)componentInParent.content != (Object)(object)val)
			{
				Plugin.LogSource.LogWarning((object)"[BetterServerScrolling] Could not match levelListContainer to its ScrollRect content; leaving the server list unchanged.");
				return false;
			}
			RectTransform val2 = componentInParent.viewport;
			if ((Object)(object)val2 == (Object)null)
			{
				Transform transform = ((Component)componentInParent).transform;
				val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			}
			if (!((Object)(object)val2 == (Object)null))
			{
				Rect rect = val2.rect;
				if (!(((Rect)(ref rect)).height <= 0f))
				{
					serverListContent = val;
					serverListScrollRect = componentInParent;
					serverListViewport = val2;
					activeServerListScrollRect = componentInParent;
					if (!serverListHookLogged)
					{
						Plugin.LogSource.LogInfo((object)"[BetterServerScrolling] Hook succeeded: matched the server list content to its ScrollRect.");
						serverListHookLogged = true;
					}
					return true;
				}
			}
			Plugin.LogSource.LogWarning((object)"[BetterServerScrolling] Could not resolve a valid server list viewport; leaving the server list unchanged.");
			return false;
		}

		private static bool TryGetVisibleServerCount(SteamLobbyManager steamLobbyManager, out int visibleServerCount)
		{
			visibleServerCount = 0;
			try
			{
				FieldInfo field = typeof(SteamLobbyManager).GetField("lobbySlotPositionOffset", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field == null)
				{
					Plugin.LogSource.LogWarning((object)"[BetterServerScrolling] Could not access SteamLobbyManager.lobbySlotPositionOffset.");
					return false;
				}
				if (!(field.GetValue(steamLobbyManager) is float num))
				{
					Plugin.LogSource.LogWarning((object)"[BetterServerScrolling] SteamLobbyManager.lobbySlotPositionOffset had an unexpected value.");
					return false;
				}
				int num2 = Mathf.RoundToInt((0f - num) / 42f);
				if (num2 < 0 || Mathf.Abs(num + (float)num2 * 42f) > 0.25f)
				{
					Plugin.LogSource.LogWarning((object)"[BetterServerScrolling] Server row offset did not match the v81 42-unit placement rule.");
					return false;
				}
				visibleServerCount = num2;
				return true;
			}
			catch (Exception ex)
			{
				Plugin.LogSource.LogWarning((object)("[BetterServerScrolling] Failed to read the populated server count: " + ex.Message));
				return false;
			}
		}

		private static bool TryMeasureVisibleServerRows(RectTransform serverListContent, int visibleServerCount, List<ServerRowPositionSnapshot> serverRowPositions, out float requiredContentHeight)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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_00c5: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
			requiredContentHeight = 0f;
			bool[] array = new bool[visibleServerCount];
			float num = float.PositiveInfinity;
			for (int i = 0; i < ((Transform)serverListContent).childCount; i++)
			{
				Transform child = ((Transform)serverListContent).GetChild(i);
				RectTransform val = (RectTransform)(object)((child is RectTransform) ? child : null);
				if ((Object)(object)val == (Object)null || (Object)(object)((Component)child).GetComponentInChildren<LobbySlot>() == (Object)null)
				{
					continue;
				}
				if (!Mathf.Approximately(val.anchorMin.y, val.anchorMax.y))
				{
					return false;
				}
				int num2 = Mathf.RoundToInt((0f - val.anchoredPosition.y) / 42f);
				if (num2 < 0 || num2 >= visibleServerCount)
				{
					continue;
				}
				float num3 = (float)(-num2) * 42f;
				if (Mathf.Abs(val.anchoredPosition.y - num3) > 0.25f)
				{
					continue;
				}
				array[num2] = true;
				serverRowPositions.Add(new ServerRowPositionSnapshot(val, ((Transform)val).position));
				Vector3[] array2 = (Vector3[])(object)new Vector3[4];
				val.GetWorldCorners(array2);
				for (int j = 0; j < array2.Length; j++)
				{
					float y = ((Transform)serverListContent).InverseTransformPoint(array2[j]).y;
					if (y < num)
					{
						num = y;
					}
				}
			}
			for (int k = 0; k < array.Length; k++)
			{
				if (!array[k])
				{
					return false;
				}
			}
			if (float.IsPositiveInfinity(num))
			{
				return false;
			}
			Rect rect = serverListContent.rect;
			requiredContentHeight = ((Rect)(ref rect)).yMax - num;
			return requiredContentHeight >= 0f;
		}

		private static void ResizeServerListContentPreservingTop(RectTransform serverListContent, float targetContentHeight, List<ServerRowPositionSnapshot>? serverRowPositions)
		{
			//IL_0010: 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)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//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_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_003f: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			if (targetContentHeight <= 0f)
			{
				return;
			}
			Rect rect = serverListContent.rect;
			Vector3 val = ((Transform)serverListContent).TransformPoint(new Vector3(0f, ((Rect)(ref rect)).yMax, 0f));
			Vector2 sizeDelta = serverListContent.sizeDelta;
			ref float y = ref sizeDelta.y;
			float num = y;
			rect = serverListContent.rect;
			y = num + (targetContentHeight - ((Rect)(ref rect)).height);
			serverListContent.sizeDelta = sizeDelta;
			Canvas.ForceUpdateCanvases();
			rect = serverListContent.rect;
			Vector3 val2 = ((Transform)serverListContent).TransformPoint(new Vector3(0f, ((Rect)(ref rect)).yMax, 0f));
			((Transform)serverListContent).position = ((Transform)serverListContent).position + (val - val2);
			if (serverRowPositions == null)
			{
				return;
			}
			for (int i = 0; i < serverRowPositions.Count; i++)
			{
				ServerRowPositionSnapshot serverRowPositionSnapshot = serverRowPositions[i];
				if ((Object)(object)serverRowPositionSnapshot.RowRectTransform != (Object)null)
				{
					((Transform)serverRowPositionSnapshot.RowRectTransform).position = serverRowPositionSnapshot.WorldPosition;
				}
			}
		}
	}
}