Decompiled source of BoplAbilityBlacklist v0.1.4

BoplAbilityBlacklist.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BoplAbilityBlacklist")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Blacklist abilities from random selection and mark them in the ability grid.")]
[assembly: AssemblyFileVersion("0.1.4.0")]
[assembly: AssemblyInformationalVersion("0.1.4+67e9ba466516150c8f52ea2ac491df916d45c3d1")]
[assembly: AssemblyProduct("BoplAbilityBlacklist")]
[assembly: AssemblyTitle("BoplAbilityBlacklist")]
[assembly: AssemblyVersion("0.1.4.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 BoplAbilityBlacklist
{
	public sealed class AbilityGridClickHandler : MonoBehaviour, IPointerClickHandler, IEventSystemHandler
	{
		public int SelectionIndex { get; set; }

		public AbilityGridEntry Entry { get; set; } = null;


		public void OnPointerClick(PointerEventData eventData)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Invalid comparison between Unknown and I4
			AbilityGrid value = Traverse.Create((object)Entry).Field<AbilityGrid>("abilityGrid").Value;
			if ((Object)(object)value == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Right-click toggle could not resolve the ability grid.");
			}
			else if ((int)eventData.button == 1)
			{
				ToggleBlacklist(value);
			}
			else if ((int)eventData.button == 0)
			{
				value.CloseGrid();
			}
		}

		private void ToggleBlacklist(AbilityGrid abilityGrid)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			HashSet<int> disabledAbilities = Plugin.Instance.GetDisabledAbilities();
			if (!disabledAbilities.Add(SelectionIndex))
			{
				disabledAbilities.Remove(SelectionIndex);
			}
			Plugin.Instance.SaveDisabledAbilities(disabledAbilities);
			bool flag = disabledAbilities.Contains(SelectionIndex);
			Entry.SetColor(flag ? Color.red : ((Graphic)abilityGrid.borderImage).color);
			Plugin.Log.LogInfo((object)string.Format("{0} ability index {1}.", flag ? "Disabled" : "Enabled", SelectionIndex));
		}
	}
	internal static class BlacklistState
	{
		public static HashSet<int> Parse(string raw)
		{
			HashSet<int> hashSet = new HashSet<int>();
			string[] array = raw.Split(new char[3] { ',', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array)
			{
				string text2 = text.Trim();
				if (text2.Length != 0 && int.TryParse(text2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
				{
					hashSet.Add(result);
				}
			}
			return hashSet;
		}

		public static string Serialize(IEnumerable<int> disabledAbilities)
		{
			return string.Join(",", disabledAbilities.OrderBy((int value) => value));
		}
	}
	[BepInPlugin("com.collin.boplabilityblacklist", "Bopl Ability Blacklist", "0.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.collin.boplabilityblacklist";

		public const string PluginName = "Bopl Ability Blacklist";

		public const string PluginVersion = "0.1.0";

		private Harmony? _harmony;

		internal ConfigEntry<string> DisabledAbilitiesRaw = null;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			Log.LogInfo((object)"Plugin.Awake fired.");
			DisabledAbilitiesRaw = ((BaseUnityPlugin)this).Config.Bind<string>("Abilities", "DisabledAbilities", string.Empty, "Comma-separated ability selection indices to exclude from random and mark in the grid.");
			SceneManager.sceneLoaded += OnSceneLoaded;
			_harmony = new Harmony("com.collin.boplabilityblacklist");
			_harmony.PatchAll();
			string[] array = (from method in _harmony.GetPatchedMethods().Where(delegate(MethodBase method)
				{
					Patches patchInfo = Harmony.GetPatchInfo(method);
					return patchInfo != null && patchInfo.Owners.Contains("com.collin.boplabilityblacklist");
				})
				select method.DeclaringType?.Name + "." + method.Name into name
				orderby name
				select name).ToArray();
			Log.LogInfo((object)string.Format("Patched {0} methods: {1}", array.Length, string.Join(", ", array)));
			Log.LogInfo((object)"Bopl Ability Blacklist 0.1.0 loaded.");
		}

		private void Start()
		{
			Log.LogInfo((object)"Plugin.Start fired.");
		}

		private void OnEnable()
		{
			Log.LogInfo((object)"Plugin.OnEnable fired.");
		}

		private void OnDisable()
		{
			Log.LogInfo((object)"Plugin.OnDisable fired.");
		}

		private void OnDestroy()
		{
			Log.LogWarning((object)"Plugin.OnDestroy fired. Keeping Harmony patches active for diagnostics.");
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			int num = Object.FindObjectsOfType<SelectAbility>().Length;
			int num2 = Object.FindObjectsOfType<AbilityGridEntry>().Length;
			int num3 = Object.FindObjectsOfType<AbilityGrid>().Length;
			int rootCount = ((Scene)(ref scene)).rootCount;
			bool flag = (Object)(object)GameObject.Find("Canvas") != (Object)null;
			bool flag2 = (Object)(object)GameObject.Find("Rectangle1") != (Object)null;
			Log.LogInfo((object)$"sceneLoaded: scene='{((Scene)(ref scene)).name}', mode={mode}, roots={rootCount}, selectAbilities={num}, abilityGrids={num3}, abilityGridEntries={num2}, canvas={flag}, rectangle1={flag2}");
		}

		internal HashSet<int> GetDisabledAbilities()
		{
			return BlacklistState.Parse(DisabledAbilitiesRaw.Value);
		}

		internal void SaveDisabledAbilities(IEnumerable<int> disabledAbilities)
		{
			DisabledAbilitiesRaw.Value = BlacklistState.Serialize(disabledAbilities);
			((BaseUnityPlugin)this).Config.Save();
		}
	}
}
namespace BoplAbilityBlacklist.Patches
{
	[HarmonyPatch(typeof(AbilityGridEntry))]
	internal static class AbilityGridEntryPatch
	{
		private static bool _loggedInit;

		[HarmonyPostfix]
		[HarmonyPatch("Init")]
		private static void InitPostfix()
		{
			if (!_loggedInit)
			{
				Plugin.Log.LogInfo((object)"AbilityGridEntry.Init patch fired.");
				_loggedInit = true;
			}
		}
	}
	[HarmonyPatch(typeof(AbilityGrid))]
	internal static class AbilityGridPatch
	{
		private static bool _loggedUpdate;

		private static bool _loggedControllerToggle;

		private static bool _loggedControllerProbe;

		private static bool _loggedInactiveGate;

		private static bool _loggedControllerDisableBlockedBySelection;

		private static int _controllerProbeButtonLogs;

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void UpdatePostfix(AbilityGrid __instance)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_0168: Unknown result type (might be due to invalid IL or missing references)
			if (!_loggedUpdate)
			{
				Plugin.Log.LogInfo((object)"AbilityGrid.Update patch fired.");
				_loggedUpdate = true;
			}
			if (!_loggedControllerProbe)
			{
				_loggedControllerProbe = true;
				string[] value = ((IEnumerable<Gamepad>)(object)Gamepad.all).Select((Gamepad g) => ((InputControl)g).displayName ?? ((InputControl)g).name).ToArray();
				string[] value2 = ((IEnumerable<Joystick>)(object)Joystick.all).Select((Joystick j) => ((InputControl)j).displayName ?? ((InputControl)j).name).ToArray();
				Plugin.Log.LogInfo((object)string.Format("ControllerProbe: gamepads={0} [{1}], joysticks={2} [{3}]", Gamepad.all.Count, string.Join(" | ", value), Joystick.all.Count, string.Join(" | ", value2)));
			}
			AbilityGridEntry[] value3 = Traverse.Create((object)__instance).Field<AbilityGridEntry[]>("grid").Value;
			if (value3 == null)
			{
				return;
			}
			HashSet<int> disabledAbilities = Plugin.Instance.GetDisabledAbilities();
			for (int i = 1; i < value3.Length; i++)
			{
				AbilityGridEntry val = value3[i];
				if (!((Object)(object)val == (Object)null))
				{
					val.SetColor(disabledAbilities.Contains(i) ? Color.red : ((Graphic)__instance.borderImage).color);
				}
			}
			HandleControllerToggle(__instance, value3, disabledAbilities);
		}

		private static void HandleControllerToggle(AbilityGrid grid, AbilityGridEntry[] entries, HashSet<int> disabledAbilities)
		{
			//IL_007a: 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_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			if (!Traverse.Create((object)grid).Field<bool>("isActive").Value && !_loggedInactiveGate)
			{
				_loggedInactiveGate = true;
				Plugin.Log.LogInfo((object)"ControllerProbe: AbilityGrid.isActive was false; using SelectedIcon-based gating instead.");
			}
			int value = Traverse.Create((object)grid).Method("get_SelectedIcon", Array.Empty<object>()).GetValue<int>();
			if (value <= 0 || value >= entries.Length)
			{
				return;
			}
			Gamepad[] array = ((IEnumerable<Gamepad>)(object)Gamepad.all).Where((Gamepad g) => g.buttonWest.wasPressedThisFrame).ToArray();
			bool value2 = Traverse.Create((object)grid).Field<bool>("usesKeyboardAndMouse").Value;
			Gamepad value3 = Traverse.Create((object)grid).Field<Gamepad>("gamepad").Value;
			if (_controllerProbeButtonLogs < 40 && array.Length != 0)
			{
				_controllerProbeButtonLogs++;
				string arg = string.Join(" | ", array.Select((Gamepad g) => ((InputControl)g).displayName ?? ((InputControl)g).name));
				Plugin.Log.LogInfo((object)string.Format("ControllerProbe: buttonWest down from gamepads=[{0}], gridUsesKeyboardMouse={1}, gridGamepad='{2}'.", arg, value2, ((value3 != null) ? ((InputControl)value3).displayName : null) ?? ((value3 != null) ? ((InputControl)value3).name : null) ?? "null"));
			}
			bool flag = array.Length != 0;
			bool flag2 = false;
			Enumerator<Joystick> enumerator = Joystick.all.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					Joystick current = enumerator.Current;
					foreach (ButtonControl item in ((IEnumerable)(object)((InputDevice)current).allControls).OfType<ButtonControl>())
					{
						if (item.wasPressedThisFrame)
						{
							if (_controllerProbeButtonLogs < 20)
							{
								_controllerProbeButtonLogs++;
								Plugin.Log.LogInfo((object)("ControllerProbe: joystick='" + (((InputControl)current).displayName ?? ((InputControl)current).name) + "' button='" + ((InputControl)item).name + "' pressed."));
							}
							bool flag3;
							switch (((InputControl)item).name)
							{
							case "button2":
							case "button3":
							case "buttonWest":
								flag3 = true;
								break;
							default:
								flag3 = false;
								break;
							}
							if (flag3)
							{
								flag2 = true;
							}
						}
					}
				}
			}
			finally
			{
				((IDisposable)enumerator).Dispose();
			}
			if ((!flag && !flag2) || (flag && (value2 || (value3 != null && !array.Contains(value3)))) || (flag2 && value2))
			{
				return;
			}
			bool flag4 = disabledAbilities.Contains(value);
			if (!flag4 && AbilitySelectionGuard.TryGetSelectionHolder(value, out string holderInfo))
			{
				if (!_loggedControllerDisableBlockedBySelection)
				{
					_loggedControllerDisableBlockedBySelection = true;
					Plugin.Log.LogInfo((object)"Controller disable block fired because ability is currently selected by a player.");
				}
				Plugin.Log.LogInfo((object)$"Blocked disabling ability index {value} via controller X because it is currently selected ({holderInfo}).");
				return;
			}
			if (flag4)
			{
				disabledAbilities.Remove(value);
			}
			else
			{
				disabledAbilities.Add(value);
			}
			Plugin.Instance.SaveDisabledAbilities(disabledAbilities);
			bool flag5 = disabledAbilities.Contains(value);
			AbilityGridEntry val = entries[value];
			if ((Object)(object)val != (Object)null)
			{
				val.SetColor(flag5 ? Color.red : ((Graphic)grid.borderImage).color);
			}
			if (!_loggedControllerToggle)
			{
				_loggedControllerToggle = true;
				Plugin.Log.LogInfo((object)"Controller toggle fired via X/buttonWest on active ability grid.");
			}
			Plugin.Log.LogInfo((object)string.Format("{0} ability index {1} via controller X toggle (gamepadWest={2}, joystickX={3}). disabledList=[{4}]", flag5 ? "Disabled" : "Enabled", value, flag, flag2, string.Join(",", disabledAbilities.OrderBy((int i) => i))));
		}
	}
	internal static class AbilitySelectionGuard
	{
		internal static bool TryGetSelectionHolder(int abilityIndex, out string holderInfo)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Invalid comparison between Unknown and I4
			holderInfo = string.Empty;
			if (abilityIndex <= 0)
			{
				return false;
			}
			CharacterSelectBox[] array = Object.FindObjectsOfType<CharacterSelectBox>();
			CharacterSelectBox[] array2 = array;
			foreach (CharacterSelectBox val in array2)
			{
				CharSelectMenu value = Traverse.Create((object)val).Field<CharSelectMenu>("menuState").Value;
				if ((int)value == 0)
				{
					continue;
				}
				List<SelectableMonoBehaviour> value2 = Traverse.Create((object)val).Field<List<SelectableMonoBehaviour>>("selectables").Value;
				if (value2 == null)
				{
					continue;
				}
				int value3 = Traverse.Create((object)val).Field<int>("RectangleIndex").Value;
				int num = 0;
				foreach (SelectableMonoBehaviour item in value2)
				{
					SelectAbility val2 = (SelectAbility)(object)((item is SelectAbility) ? item : null);
					if (val2 != null)
					{
						num++;
						int value4 = Traverse.Create((object)val2).Field<int>("selectedIndex").Value;
						int num2 = value4 - 1;
						if (num2 == abilityIndex)
						{
							holderInfo = $"playerBox={value3}, slot={num}, selectedSprite={value4}";
							return true;
						}
					}
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(CallOnHover))]
	internal static class CallOnHoverPatch
	{
		private static bool _loggedClickPath;

		private static bool _loggedDisableBlockedBySelection;

		[HarmonyPrefix]
		[HarmonyPatch("OnPointerClick")]
		private static bool OnPointerClickPrefix(CallOnHover __instance, PointerEventData eventData)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Invalid comparison between Unknown and I4
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			if (!_loggedClickPath)
			{
				_loggedClickPath = true;
				Plugin.Log.LogInfo((object)"CallOnHover.OnPointerClick patch fired.");
			}
			AbilityGridEntry val = ((Component)__instance).GetComponent<AbilityGridEntry>() ?? ((Component)__instance).GetComponentInParent<AbilityGridEntry>();
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			int value = Traverse.Create((object)val).Field<int>("index").Value;
			AbilityGrid value2 = Traverse.Create((object)val).Field<AbilityGrid>("abilityGrid").Value;
			HashSet<int> disabledAbilities = Plugin.Instance.GetDisabledAbilities();
			if (eventData == null || (int)eventData.button != 1)
			{
				return true;
			}
			bool flag = disabledAbilities.Contains(value);
			if (!flag && AbilitySelectionGuard.TryGetSelectionHolder(value, out string holderInfo))
			{
				if (!_loggedDisableBlockedBySelection)
				{
					_loggedDisableBlockedBySelection = true;
					Plugin.Log.LogInfo((object)"Disable block fired because ability is currently selected by a player.");
				}
				Plugin.Log.LogInfo((object)$"Blocked disabling ability index {value} via right-click because it is currently selected ({holderInfo}).");
				return false;
			}
			if (flag)
			{
				disabledAbilities.Remove(value);
			}
			else
			{
				disabledAbilities.Add(value);
			}
			Plugin.Instance.SaveDisabledAbilities(disabledAbilities);
			bool flag2 = disabledAbilities.Contains(value);
			int num = -1;
			if ((Object)(object)value2 != (Object)null)
			{
				num = Traverse.Create((object)value2).Method("get_SelectedIcon", Array.Empty<object>()).GetValue<int>();
			}
			if ((Object)(object)value2 != (Object)null)
			{
				val.SetColor(flag2 ? Color.red : ((Graphic)value2.borderImage).color);
			}
			Plugin.Log.LogInfo((object)string.Format("RightClickToggle: entryIndex={0}, abilityChoiceEquivalent={1}, selectedIcon={2}, nowDisabled={3}, disabledList=[{4}]", value, value + 1, num, flag2, string.Join(",", disabledAbilities.OrderBy((int i) => i))));
			Plugin.Log.LogInfo((object)string.Format("{0} ability index {1} via right-click.", flag2 ? "Disabled" : "Enabled", value));
			return false;
		}
	}
	[HarmonyPatch]
	internal static class CanaryPatch
	{
		private static bool _loggedPrintTextStart;

		private static int _callOnHoverClicksLogged;

		private static IEnumerable<MethodBase> TargetMethods()
		{
			List<MethodBase> list = new List<MethodBase>();
			Type type = AccessTools.TypeByName("printText");
			MethodInfo methodInfo = AccessTools.Method(type, "Start", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				list.Add(methodInfo);
			}
			Type type2 = AccessTools.TypeByName("CallOnHover");
			MethodInfo methodInfo2 = AccessTools.Method(type2, "OnPointerClick", new Type[1] { typeof(PointerEventData) }, (Type[])null);
			if (methodInfo2 != null)
			{
				list.Add(methodInfo2);
			}
			return list;
		}

		private static void Postfix(MethodBase __originalMethod, object[] __args)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			string a = __originalMethod.DeclaringType?.Name + "." + __originalMethod.Name;
			if (string.Equals(a, "printText.Start", StringComparison.Ordinal))
			{
				if (!_loggedPrintTextStart)
				{
					_loggedPrintTextStart = true;
					Plugin.Log.LogInfo((object)"Canary: printText.Start patch fired.");
				}
			}
			else if (string.Equals(a, "CallOnHover.OnPointerClick", StringComparison.Ordinal) && _callOnHoverClicksLogged < 8)
			{
				_callOnHoverClicksLogged++;
				object? obj = __args.FirstOrDefault();
				PointerEventData val = (PointerEventData)((obj is PointerEventData) ? obj : null);
				object obj2;
				if (val == null)
				{
					obj2 = null;
				}
				else
				{
					InputButton button = val.button;
					obj2 = ((object)(InputButton)(ref button)).ToString();
				}
				if (obj2 == null)
				{
					obj2 = "null";
				}
				string arg = (string)obj2;
				Plugin.Log.LogInfo((object)$"Canary: CallOnHover.OnPointerClick fired. button={arg}, count={_callOnHoverClicksLogged}.");
			}
		}
	}
	[HarmonyPatch(typeof(CharacterSelectBox))]
	internal static class CharacterSelectDefaultAbilityPatch
	{
		private static bool _loggedJoinSanitize;

		private static bool _loggedLoadSanitize;

		[HarmonyPostfix]
		[HarmonyPatch("OnEnterSelect")]
		private static void OnEnterSelectPostfix(CharacterSelectBox __instance)
		{
			SanitizeAbilitySelections(__instance, "OnEnterSelect", ref _loggedJoinSanitize);
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetToPlayerChoices")]
		private static void SetToPlayerChoicesPostfix(CharacterSelectBox __instance)
		{
			SanitizeAbilitySelections(__instance, "SetToPlayerChoices", ref _loggedLoadSanitize);
		}

		private static void SanitizeAbilitySelections(CharacterSelectBox box, string source, ref bool logged)
		{
			HashSet<int> disabledAbilities = Plugin.Instance.GetDisabledAbilities();
			if (disabledAbilities.Count == 0)
			{
				return;
			}
			List<SelectableMonoBehaviour> value = Traverse.Create((object)box).Field<List<SelectableMonoBehaviour>>("selectables").Value;
			if (value == null)
			{
				return;
			}
			SelectAbility[] array = value.OfType<SelectAbility>().ToArray();
			if (array.Length == 0)
			{
				return;
			}
			HashSet<int> hashSet = new HashSet<int>(from selector in array
				select Traverse.Create((object)selector).Field<int>("selectedIndex").Value into selectedIndex
				where IsEnabledSelection(selectedIndex, disabledAbilities)
				select selectedIndex);
			bool flag = false;
			SelectAbility[] array2 = array;
			foreach (SelectAbility val in array2)
			{
				int value2 = Traverse.Create((object)val).Field<int>("selectedIndex").Value;
				if (!IsBlacklistedSelection(value2, disabledAbilities))
				{
					continue;
				}
				hashSet.Remove(value2);
				int valueOrDefault = (Traverse.Create((object)val).Field<NamedSpriteList>("abilityIcons").Value?.sprites?.Count).GetValueOrDefault();
				if (valueOrDefault > 0)
				{
					int num = FindClosestEnabledSelection(value2, valueOrDefault, disabledAbilities, hashSet);
					if (num > 1 && num != value2)
					{
						((SelectableMonoBehaviour)val).Select(num);
						hashSet.Add(num);
						flag = true;
						Plugin.Log.LogInfo((object)$"{source} replaced blacklisted default spriteIndex={value2}, abilityIndex={value2 - 1} with spriteIndex={num}, abilityIndex={num - 1}.");
					}
				}
			}
			if (flag)
			{
				Traverse.Create((object)box).Method("UpdatePlayerInit", Array.Empty<object>()).GetValue();
				if (!logged)
				{
					logged = true;
					Plugin.Log.LogInfo((object)(source + " sanitized starting abilities against the blacklist."));
				}
			}
		}

		private static int FindClosestEnabledSelection(int startIndex, int spriteCount, HashSet<int> disabledAbilities, HashSet<int> reservedSelections)
		{
			for (int i = 1; i < spriteCount; i++)
			{
				int num = startIndex - i;
				if (IsEnabledSelection(num, spriteCount, disabledAbilities, reservedSelections))
				{
					return num;
				}
				int num2 = startIndex + i;
				if (IsEnabledSelection(num2, spriteCount, disabledAbilities, reservedSelections))
				{
					return num2;
				}
			}
			for (int j = 1; j < spriteCount; j++)
			{
				int num3 = startIndex - j;
				if (IsEnabledSelection(num3, spriteCount, disabledAbilities))
				{
					return num3;
				}
				int num4 = startIndex + j;
				if (IsEnabledSelection(num4, spriteCount, disabledAbilities))
				{
					return num4;
				}
			}
			return startIndex;
		}

		private static bool IsBlacklistedSelection(int selectedIndex, HashSet<int> disabledAbilities)
		{
			int num = selectedIndex - 1;
			return num > 0 && disabledAbilities.Contains(num);
		}

		private static bool IsEnabledSelection(int selectedIndex, HashSet<int> disabledAbilities)
		{
			int num = selectedIndex - 1;
			return selectedIndex > 1 && num > 0 && !disabledAbilities.Contains(num);
		}

		private static bool IsEnabledSelection(int selectedIndex, int spriteCount, HashSet<int> disabledAbilities, HashSet<int> reservedSelections)
		{
			return selectedIndex > 1 && selectedIndex < spriteCount && IsEnabledSelection(selectedIndex, disabledAbilities) && !reservedSelections.Contains(selectedIndex);
		}

		private static bool IsEnabledSelection(int selectedIndex, int spriteCount, HashSet<int> disabledAbilities)
		{
			return selectedIndex > 1 && selectedIndex < spriteCount && IsEnabledSelection(selectedIndex, disabledAbilities);
		}
	}
	[HarmonyPatch(typeof(CharacterSelectBox))]
	internal static class CharacterSelectBoxDiagnosticsPatch
	{
		private static bool _loggedAwake;

		private static bool _loggedEnterAbilityGrid;

		private static bool _loggedClickEnterAbilityGrid;

		private static bool _loggedUpdate;

		private static bool _loggedCloseAbilityGridBlock;

		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		private static void AwakePostfix(CharacterSelectBox __instance)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (!_loggedAwake)
			{
				_loggedAwake = true;
				AbilityGrid value = Traverse.Create((object)__instance).Field<AbilityGrid>("abilityGrid").Value;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)$"CharacterSelectBox.Awake fired in scene '{((Scene)(ref activeScene)).name}'. abilityGridNull={(Object)(object)value == (Object)null}");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("ClickEnterAbilityGrid")]
		private static void ClickEnterAbilityGridPostfix()
		{
			//IL_001d: 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)
			if (!_loggedClickEnterAbilityGrid)
			{
				_loggedClickEnterAbilityGrid = true;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)("CharacterSelectBox.ClickEnterAbilityGrid fired in scene '" + ((Scene)(ref activeScene)).name + "'."));
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("EnterAbilityGrid")]
		private static void EnterAbilityGridPostfix(CharacterSelectBox __instance)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (!_loggedEnterAbilityGrid)
			{
				_loggedEnterAbilityGrid = true;
				AbilityGrid value = Traverse.Create((object)__instance).Field<AbilityGrid>("abilityGrid").Value;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)$"CharacterSelectBox.EnterAbilityGrid fired in scene '{((Scene)(ref activeScene)).name}'. abilityGridNull={(Object)(object)value == (Object)null}");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void UpdatePostfix(CharacterSelectBox __instance)
		{
			//IL_0082: 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)
			if (!_loggedUpdate)
			{
				_loggedUpdate = true;
				AbilityGrid value = Traverse.Create((object)__instance).Field<AbilityGrid>("abilityGrid").Value;
				int value2 = Traverse.Create((object)__instance).Field<int>("ab1Index").Value;
				int value3 = Traverse.Create((object)__instance).Field<int>("ab2Index").Value;
				int value4 = Traverse.Create((object)__instance).Field<int>("ab3Index").Value;
				ManualLogSource log = Plugin.Log;
				object[] array = new object[5];
				Scene activeScene = SceneManager.GetActiveScene();
				array[0] = ((Scene)(ref activeScene)).name;
				array[1] = (Object)(object)value == (Object)null;
				array[2] = value2;
				array[3] = value3;
				array[4] = value4;
				log.LogInfo((object)string.Format("CharacterSelectBox.Update fired in scene '{0}'. abilityGridNull={1}, abilities=[{2},{3},{4}]", array));
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("CloseAbilityGrid")]
		private static bool CloseAbilityGridPrefix(CharacterSelectBox __instance, int __0)
		{
			int num = __0 - 1;
			if (num <= 0)
			{
				return true;
			}
			HashSet<int> disabledAbilities = Plugin.Instance.GetDisabledAbilities();
			AbilityGrid value = Traverse.Create((object)__instance).Field<AbilityGrid>("abilityGrid").Value;
			int num2 = (((Object)(object)value == (Object)null) ? (-1) : Traverse.Create((object)value).Method("get_SelectedIcon", Array.Empty<object>()).GetValue<int>());
			bool flag = disabledAbilities.Contains(num);
			bool flag2 = num2 == num;
			Plugin.Log.LogInfo((object)$"CloseAbilityGrid: abilityChoice={__0}, abilityEntryIndex={num}, selectedIcon={num2}, selectedMatches={flag2}, shouldBlock={flag}");
			if (!flag)
			{
				return true;
			}
			if (!_loggedCloseAbilityGridBlock)
			{
				_loggedCloseAbilityGridBlock = true;
				Plugin.Log.LogInfo((object)"CharacterSelectBox.CloseAbilityGrid block patch fired for disabled abilities.");
			}
			Plugin.Log.LogInfo((object)$"Blocked closing ability grid for disabled index {num}.");
			return false;
		}
	}
	[HarmonyPatch(typeof(CharacterSelectHandler))]
	internal static class CharacterSelectHandlerDiagnosticsPatch
	{
		private static bool _loggedAwake;

		private static bool _loggedUpdate;

		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		private static void AwakePostfix()
		{
			//IL_001d: 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)
			if (!_loggedAwake)
			{
				_loggedAwake = true;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)("CharacterSelectHandler.Awake fired in scene '" + ((Scene)(ref activeScene)).name + "'."));
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void UpdatePostfix(CharacterSelectHandler __instance)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (!_loggedUpdate)
			{
				_loggedUpdate = true;
				CharacterSelectBox[] value = Traverse.Create((object)__instance).Field<CharacterSelectBox[]>("characterSelectBoxes").Value;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)$"CharacterSelectHandler.Update fired in scene '{((Scene)(ref activeScene)).name}'. boxes={((value == null) ? (-1) : value.Length)}");
			}
		}
	}
	[HarmonyPatch(typeof(CharacterSelectHandler_online))]
	internal static class CharacterSelectHandlerOnlineDiagnosticsPatch
	{
		private static bool _loggedAwake;

		private static bool _loggedUpdate;

		private static bool _loggedOnLobbyInit;

		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		private static void AwakePostfix()
		{
			//IL_001d: 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)
			if (!_loggedAwake)
			{
				_loggedAwake = true;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)("CharacterSelectHandler_online.Awake fired in scene '" + ((Scene)(ref activeScene)).name + "'."));
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void UpdatePostfix(CharacterSelectHandler_online __instance)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (!_loggedUpdate)
			{
				_loggedUpdate = true;
				CharacterSelectBox value = Traverse.Create((object)__instance).Field<CharacterSelectBox>("characterSelectBox").Value;
				CSBox_online[] value2 = Traverse.Create((object)__instance).Field<CSBox_online[]>("networkPlayerBoxes").Value;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)$"CharacterSelectHandler_online.Update fired in scene '{((Scene)(ref activeScene)).name}'. localBoxNull={(Object)(object)value == (Object)null}, networkBoxes={((value2 == null) ? (-1) : value2.Length)}");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("OnLobbyInit")]
		private static void OnLobbyInitPostfix()
		{
			//IL_001d: 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)
			if (!_loggedOnLobbyInit)
			{
				_loggedOnLobbyInit = true;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)("CharacterSelectHandler_online.OnLobbyInit fired in scene '" + ((Scene)(ref activeScene)).name + "'."));
			}
		}
	}
	[HarmonyPatch(typeof(CharSelectClickToJoin))]
	internal static class CharSelectClickToJoinDiagnosticsPatch
	{
		private static bool _loggedOnEnable;

		private static bool _loggedClick;

		[HarmonyPostfix]
		[HarmonyPatch("OnEnable")]
		private static void OnEnablePostfix()
		{
			//IL_001d: 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)
			if (!_loggedOnEnable)
			{
				_loggedOnEnable = true;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)("CharSelectClickToJoin.OnEnable fired in scene '" + ((Scene)(ref activeScene)).name + "'."));
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("OnPointerClick")]
		private static void OnPointerClickPostfix()
		{
			//IL_001d: 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)
			if (!_loggedClick)
			{
				_loggedClick = true;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)("CharSelectClickToJoin.OnPointerClick fired in scene '" + ((Scene)(ref activeScene)).name + "'."));
			}
		}
	}
	[HarmonyPatch(typeof(GameSessionHandler))]
	internal static class DiagnosticsGameSessionHandlerPatch
	{
		private static bool _loggedInit;

		private static bool _loggedLoadAbilitySelectScene;

		[HarmonyPostfix]
		[HarmonyPatch("Init")]
		private static void InitPostfix()
		{
			//IL_001d: 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)
			if (!_loggedInit)
			{
				_loggedInit = true;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)("GameSessionHandler.Init fired in scene '" + ((Scene)(ref activeScene)).name + "'."));
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("LoadAbilitySelectScene")]
		private static void LoadAbilitySelectScenePostfix()
		{
			//IL_001d: 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)
			if (!_loggedLoadAbilitySelectScene)
			{
				_loggedLoadAbilitySelectScene = true;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)("GameSessionHandler.LoadAbilitySelectScene fired in scene '" + ((Scene)(ref activeScene)).name + "'."));
			}
		}
	}
	[HarmonyPatch(typeof(SelectAbility))]
	internal static class DiagnosticsSelectAbilityPatch
	{
		private static bool _loggedAwake;

		private static bool _loggedSelect;

		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		private static void AwakePostfix()
		{
			//IL_001d: 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)
			if (!_loggedAwake)
			{
				_loggedAwake = true;
				ManualLogSource log = Plugin.Log;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)("SelectAbility.Awake fired in scene '" + ((Scene)(ref activeScene)).name + "'."));
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Select")]
		[HarmonyPatch(new Type[] { typeof(int) })]
		private static void SelectPostfix(int index)
		{
			//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)
			if (!_loggedSelect)
			{
				_loggedSelect = true;
				ManualLogSource log = Plugin.Log;
				object arg = index;
				Scene activeScene = SceneManager.GetActiveScene();
				log.LogInfo((object)$"SelectAbility.Select fired with index {arg} in scene '{((Scene)(ref activeScene)).name}'.");
			}
		}
	}
	[HarmonyPatch(typeof(MidGameAbilitySelect))]
	internal static class MidGameAbilitySelectPatch
	{
		private static bool _loggedPatch;

		private static bool _loggedSkip;

		private static bool _loggedNoEnabledFallback;

		[HarmonyPostfix]
		[HarmonyPatch("Left")]
		private static void LeftPostfix(MidGameAbilitySelect __instance)
		{
			SkipBlacklistedSelection(__instance, moveForward: true);
		}

		[HarmonyPostfix]
		[HarmonyPatch("Right")]
		private static void RightPostfix(MidGameAbilitySelect __instance)
		{
			SkipBlacklistedSelection(__instance, moveForward: false);
		}

		private static void SkipBlacklistedSelection(MidGameAbilitySelect selector, bool moveForward)
		{
			HashSet<int> disabledAbilities = Plugin.Instance.GetDisabledAbilities();
			if (disabledAbilities.Count == 0)
			{
				return;
			}
			if (!_loggedPatch)
			{
				_loggedPatch = true;
				Plugin.Log.LogInfo((object)"MidGameAbilitySelect.Left/Right scroller patch fired.");
			}
			int[] value = Traverse.Create((object)selector).Field<int[]>("XPos").Value;
			if (value == null || value.Length == 0)
			{
				return;
			}
			int value2 = Traverse.Create((object)selector).Field<int>("YPos").Value;
			if (value2 < 0 || value2 >= value.Length)
			{
				return;
			}
			int num = value[value2];
			if (!IsBlacklistedSelection(num, disabledAbilities))
			{
				return;
			}
			int valueOrDefault = (Traverse.Create((object)selector).Field<NamedSpriteList>("localAbilityIcons").Value?.sprites?.Count).GetValueOrDefault();
			if (valueOrDefault <= 0)
			{
				return;
			}
			int num2 = FindNextEnabledSelection(num, moveForward, valueOrDefault, disabledAbilities);
			if (num2 == num || num2 <= 0)
			{
				if (!_loggedNoEnabledFallback)
				{
					_loggedNoEnabledFallback = true;
					Plugin.Log.LogWarning((object)"MidGameAbilitySelect could not find an enabled replacement for a disabled selection.");
				}
				return;
			}
			value[value2] = num2;
			Traverse.Create((object)selector).Method("UpdatePlayerAbilityChoices", Array.Empty<object>()).GetValue();
			if (!_loggedSkip)
			{
				_loggedSkip = true;
				Plugin.Log.LogInfo((object)"MidGameAbilitySelect scroller skip fired for disabled abilities.");
			}
			Plugin.Log.LogInfo((object)string.Format("MidGameAbilitySelect {0} skipped disabled spriteIndex={1}, abilityIndex={2}, replacementSpriteIndex={3}, replacementAbilityIndex={4}.", moveForward ? "Left" : "Right", num, num - 1, num2, num2 - 1));
		}

		private static int FindNextEnabledSelection(int startIndex, bool moveForward, int spriteCount, HashSet<int> disabledAbilities)
		{
			int num = (moveForward ? 1 : (-1));
			int num2 = startIndex;
			for (int i = 0; i < spriteCount; i++)
			{
				num2 = (num2 + num + spriteCount) % spriteCount;
				if (num2 != 0 && !IsBlacklistedSelection(num2, disabledAbilities))
				{
					return num2;
				}
			}
			return startIndex;
		}

		private static bool IsBlacklistedSelection(int selectedIndex, HashSet<int> disabledAbilities)
		{
			int num = selectedIndex - 1;
			return num > 0 && disabledAbilities.Contains(num);
		}
	}
	internal static class RandomAbilityPatch
	{
		private static bool _loggedRandomPatch;

		internal static void ApplyBlacklistToRandomResult(ref NamedSprite result, NamedSpriteList abilityIcons, NamedSpriteList abilityIconsDemo)
		{
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			if (!_loggedRandomPatch)
			{
				Plugin.Log.LogInfo((object)"RandomAbility.GetRandomAbilityPrefab patch fired.");
				_loggedRandomPatch = true;
			}
			NamedSpriteList val = (ShouldUseDlcPool() ? abilityIcons : abilityIconsDemo);
			if (val?.sprites == null)
			{
				return;
			}
			int count = val.sprites.Count;
			int num = count - 2;
			if (num <= 0)
			{
				return;
			}
			HashSet<int> disabledAbilities = Plugin.Instance.GetDisabledAbilities();
			List<int> list = new List<int>(num);
			for (int i = 2; i < count; i++)
			{
				if (!disabledAbilities.Contains(i - 1))
				{
					list.Add(i);
				}
			}
			if (list.Count == 0)
			{
				Plugin.Log.LogWarning((object)"All abilities are blacklisted. Leaving the game's original random selection unchanged.");
				return;
			}
			int index = Updater.RandomInt(0, list.Count);
			int index2 = list[index];
			result = val.sprites[index2];
		}

		private static bool ShouldUseDlcPool()
		{
			if ((Object)(object)SteamManager.instance == (Object)null)
			{
				return false;
			}
			return SteamManager.instance.dlc.HasDLC();
		}
	}
	[HarmonyPatch(typeof(RandomAbility), "GetRandomAbilityPrefab")]
	[HarmonyPatch(new Type[]
	{
		typeof(NamedSpriteList),
		typeof(NamedSpriteList)
	})]
	internal static class RandomAbilityTwoArgPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ref NamedSprite __result, NamedSpriteList abilityIcons, NamedSpriteList abilityIcons_demo)
		{
			RandomAbilityPatch.ApplyBlacklistToRandomResult(ref __result, abilityIcons, abilityIcons_demo);
		}
	}
	[HarmonyPatch(typeof(RandomAbility), "GetRandomAbilityPrefab")]
	[HarmonyPatch(new Type[]
	{
		typeof(NamedSpriteList),
		typeof(NamedSpriteList),
		typeof(Sprite)
	})]
	internal static class RandomAbilityThreeArgPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ref NamedSprite __result, NamedSpriteList abilityIcons, NamedSpriteList abilityIcons_demo)
		{
			RandomAbilityPatch.ApplyBlacklistToRandomResult(ref __result, abilityIcons, abilityIcons_demo);
		}
	}
	[HarmonyPatch(typeof(SelectAbility))]
	internal static class SelectAbilityScrollerPatch
	{
		private static bool _loggedScrollerSkip;

		[HarmonyPostfix]
		[HarmonyPatch("Move")]
		[HarmonyPatch(new Type[] { typeof(bool) })]
		private static void MovePostfix(SelectAbility __instance, bool moveRight)
		{
			HashSet<int> disabledAbilities = Plugin.Instance.GetDisabledAbilities();
			if (disabledAbilities.Count == 0)
			{
				return;
			}
			int value = Traverse.Create((object)__instance).Field<int>("selectedIndex").Value;
			if (!IsBlacklistedSelection(value, disabledAbilities))
			{
				return;
			}
			int valueOrDefault = (Traverse.Create((object)__instance).Field<NamedSpriteList>("abilityIcons").Value?.sprites?.Count).GetValueOrDefault();
			if (valueOrDefault <= 0)
			{
				return;
			}
			int num = FindNextEnabledSelection(value, moveRight, valueOrDefault, disabledAbilities);
			if (num > 0 && num != value)
			{
				((SelectableMonoBehaviour)__instance).Select(num);
				if (!_loggedScrollerSkip)
				{
					_loggedScrollerSkip = true;
					Plugin.Log.LogInfo((object)"SelectAbility.Move scroller skip fired for disabled abilities.");
				}
				Plugin.Log.LogInfo((object)$"SelectAbility.Move skipped disabled selection spriteIndex={value}, abilityIndex={value - 1}, replacementSpriteIndex={num}, replacementAbilityIndex={num - 1}, moveRight={moveRight}.");
			}
		}

		private static int FindNextEnabledSelection(int startIndex, bool moveRight, int spriteCount, HashSet<int> disabledAbilities)
		{
			int num = (moveRight ? 1 : (-1));
			int num2 = startIndex;
			for (int i = 0; i < spriteCount; i++)
			{
				num2 = (num2 + num + spriteCount) % spriteCount;
				if (num2 != 0 && !IsBlacklistedSelection(num2, disabledAbilities))
				{
					return num2;
				}
			}
			return startIndex;
		}

		private static bool IsBlacklistedSelection(int selectedIndex, HashSet<int> disabledAbilities)
		{
			int num = selectedIndex - 1;
			return num > 0 && disabledAbilities.Contains(num);
		}
	}
	[HarmonyPatch(typeof(SteamManager))]
	internal static class SteamManagerDiagnosticsPatch
	{
		private static bool _loggedCreated;

		private static bool _loggedEntered;

		private static int _lastSummaryHash;

		[HarmonyPostfix]
		[HarmonyPatch("OnLobbyCreatedCallback")]
		private static void OnLobbyCreatedCallbackPostfix()
		{
			if (!_loggedCreated)
			{
				_loggedCreated = true;
				LogRuntimeSnapshot("OnLobbyCreatedCallback");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("OnLobbyEnteredCallback")]
		private static void OnLobbyEnteredCallbackPostfix()
		{
			if (!_loggedEntered)
			{
				_loggedEntered = true;
				LogRuntimeSnapshot("OnLobbyEnteredCallback");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void UpdatePostfix()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			string text = BuildCountSummary();
			string text2 = name + "|" + text;
			int hashCode = text2.GetHashCode();
			if (hashCode != _lastSummaryHash)
			{
				_lastSummaryHash = hashCode;
				Plugin.Log.LogInfo((object)("SteamManager.Update summary: scene='" + name + "', " + text));
			}
		}

		private static void LogRuntimeSnapshot(string source)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			string[] value = (from go in ((Scene)(ref activeScene)).GetRootGameObjects()
				select ((Object)go).name into name
				orderby name
				select name).ToArray();
			Plugin.Log.LogInfo((object)(source + ": scene='" + ((Scene)(ref activeScene)).name + "', roots=[" + string.Join(", ", value) + "], " + BuildCountSummary()));
		}

		private static string BuildCountSummary()
		{
			int num = Object.FindObjectsOfType<CharacterSelectBox>().Length;
			int num2 = Object.FindObjectsOfType<CharacterSelectHandler>().Length;
			int num3 = Object.FindObjectsOfType<CharacterSelectHandler_online>().Length;
			int num4 = Object.FindObjectsOfType<CSBox_online>().Length;
			int num5 = Object.FindObjectsOfType<CharSelectClickToJoin>().Length;
			int num6 = Object.FindObjectsOfType<SelectAbility>().Length;
			int num7 = Object.FindObjectsOfType<AbilityGrid>().Length;
			int num8 = Object.FindObjectsOfType<AbilityGridEntry>().Length;
			int num9 = Object.FindObjectsOfType<MenuAbilitySelector>().Length;
			int num10 = Object.FindObjectsOfType<AbilitySelectController>().Length;
			return $"counts: CharacterSelectBox={num}, CharacterSelectHandler={num2}, CharacterSelectHandler_online={num3}, CSBox_online={num4}, CharSelectClickToJoin={num5}, SelectAbility={num6}, AbilityGrid={num7}, AbilityGridEntry={num8}, MenuAbilitySelector={num9}, AbilitySelectController={num10}";
		}
	}
}