Decompiled source of ExtraButtonSupport v1.0.0

ExtraButtonSupport.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GlobalEnums;
using GlobalSettings;
using HarmonyLib;
using HutongGames.PlayMaker;
using InControl;
using Microsoft.CodeAnalysis;
using Steamworks;
using UnityEngine;
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("ExtraButtonSupport")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+67d4550c2c94ab97d827eb3393fe6c23235a1944")]
[assembly: AssemblyProduct("ExtraButtonSupport")]
[assembly: AssemblyTitle("ExtraButtonSupport")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace ExtraButtonSupport
{
	[HarmonyPatch]
	internal static class DeviceInjection
	{
		private static bool _pollFailed;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InputManager), "AttachDevice")]
		private static void AddExtraControls(InputDevice inputDevice)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 12; i++)
			{
				inputDevice.AddControl(ExtraButtonSupportPlugin.ControlFor(i), $"Extra {i + 1}");
			}
			ManualLogSource? log = ExtraButtonSupportPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"[extra] added Extra 1-{12} to {inputDevice.Name} ({((object)inputDevice).GetType().Name}, style {inputDevice.DeviceStyle})");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InputManager), "UpdateDevices")]
		private static void FeedExtraControls(float deltaTime)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ExtraButtonSupportPlugin.Instance?.Poll();
			}
			catch (Exception arg)
			{
				Array.Clear(ExtraButtonSupportPlugin.SlotDown, 0, 12);
				if (!_pollFailed)
				{
					ManualLogSource? log = ExtraButtonSupportPlugin.Log;
					if (log != null)
					{
						log.LogError((object)$"[extra] Steam Input poll failed: {arg}");
					}
				}
				_pollFailed = true;
			}
			InputDevice activeDevice = InputManager.ActiveDevice;
			bool flag = activeDevice == null || !activeDevice.HasControl(ExtraButtonSupportPlugin.ControlFor(0));
			ulong currentTick = InputManager.CurrentTick;
			foreach (InputDevice device in InputManager.Devices)
			{
				for (int i = 0; i < 12; i++)
				{
					if (device.HasControl(ExtraButtonSupportPlugin.ControlFor(i)))
					{
						((OneAxisInputControl)device.GetControl(ExtraButtonSupportPlugin.ControlFor(i))).UpdateWithState((flag || device == activeDevice) && ExtraButtonSupportPlugin.SlotDown[i], currentTick, deltaTime);
					}
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(DeviceBindingSourceListener), "ListenForControl")]
		private static void AcceptExtraSlots(InputDevice device, ref InputControlType __result)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected I4, but got Unknown
			if (__result || device == null)
			{
				return;
			}
			for (int i = 8; i < 12; i++)
			{
				if (((OneAxisInputControl)device.GetControl(ExtraButtonSupportPlugin.ControlFor(i))).Value > 0.5f)
				{
					__result = (InputControlType)(int)ExtraButtonSupportPlugin.ControlFor(i);
					break;
				}
			}
		}
	}
	[BepInPlugin("io.github.andygobrien.extrabuttonsupport", "ExtraButtonSupport", "1.0.0")]
	public class ExtraButtonSupportPlugin : BaseUnityPlugin
	{
		internal const int Slots = 12;

		private const string ActionSet = "Default";

		internal static ExtraButtonSupportPlugin? Instance;

		internal static ManualLogSource? Log;

		internal static readonly bool[] SlotDown = new bool[12];

		private bool _initialized;

		private float _nextInitAttempt;

		private InputActionSetHandle_t _set;

		private readonly InputDigitalActionHandle_t[] _actions = (InputDigitalActionHandle_t[])(object)new InputDigitalActionHandle_t[12];

		private static readonly string[] ActionNames = BuildActionNames();

		private float _nextResolve;

		private readonly InputHandle_t[] _pads = (InputHandle_t[])(object)new InputHandle_t[16];

		private readonly EInputActionOrigin[] _origins = (EInputActionOrigin[])(object)new EInputActionOrigin[8];

		private int _padCount = -1;

		private readonly ulong[] _lastPads = new ulong[16];

		private bool _padsChanged;

		private Callback<SteamInputConfigurationLoaded_t>? _configLoaded;

		public const string Id = "io.github.andygobrien.extrabuttonsupport";

		public static string Name => "ExtraButtonSupport";

		public static string Version => "1.0.0";

		internal static InputControlType ControlFor(int slot)
		{
			if (slot < 8)
			{
				return (InputControlType)(23 + slot);
			}
			return (InputControlType)(500 + (slot - 8));
		}

		internal static int SlotFor(InputControlType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected I4, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected I4, but got Unknown
			if ((int)type < 23 || (int)type > 30)
			{
				if ((int)type < 500 || (int)type > 503)
				{
					return -1;
				}
				return 8 + (type - 500);
			}
			return type - 23;
		}

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Harmony val = new Harmony("io.github.andygobrien.extrabuttonsupport");
			val.PatchAll(typeof(DeviceInjection));
			val.PatchAll(typeof(Glyphs));
			val.PatchAll(typeof(ToolActionPatches));
			val.PatchAll(typeof(MenuRowPatches));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin " + Name + " (io.github.andygobrien.extrabuttonsupport) has loaded!"));
		}

		private void Update()
		{
			if (!_initialized)
			{
				TryInit();
			}
			else if (_padsChanged)
			{
				_padsChanged = false;
				try
				{
					LogPads();
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("[extra] controller info failed: " + ex.Message));
				}
			}
		}

		private void TryInit()
		{
			if (Time.unscaledTime < _nextInitAttempt)
			{
				return;
			}
			_nextInitAttempt = Time.unscaledTime + 1f;
			try
			{
				_configLoaded = Callback<SteamInputConfigurationLoaded_t>.Create((DispatchDelegate<SteamInputConfigurationLoaded_t>)delegate(SteamInputConfigurationLoaded_t e)
				{
					//IL_000b: 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_0016: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Unknown result type (might be due to invalid IL or missing references)
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"[extra] config loaded: app={e.m_unAppID} usesSteamInputAPI={e.m_bUsesSteamInputAPI} usesGamepadAPI={e.m_bUsesGamepadAPI}");
				});
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[extra] SteamInput.Init(true) = {SteamInput.Init(true)}");
				_initialized = true;
			}
			catch (InvalidOperationException)
			{
			}
		}

		internal void Poll()
		{
			//IL_006e: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			if (!_initialized)
			{
				return;
			}
			SteamInput.RunFrame(true);
			if (Time.unscaledTime >= _nextResolve)
			{
				_nextResolve = Time.unscaledTime + 1f;
				ResolveHandles();
			}
			int connectedControllers = SteamInput.GetConnectedControllers(_pads);
			if (PadsChanged(connectedControllers))
			{
				_padCount = connectedControllers;
				_padsChanged = true;
			}
			if (_set.m_InputActionSetHandle != 0L)
			{
				for (int i = 0; i < connectedControllers; i++)
				{
					SteamInput.ActivateActionSet(_pads[i], _set);
				}
			}
			for (int j = 0; j < 12; j++)
			{
				bool flag = false;
				for (int k = 0; k < connectedControllers; k++)
				{
					if (_actions[j].m_InputDigitalActionHandle == 0L)
					{
						break;
					}
					InputDigitalActionData_t digitalActionData = SteamInput.GetDigitalActionData(_pads[k], _actions[j]);
					flag |= digitalActionData.bActive != 0 && digitalActionData.bState != 0;
				}
				if (flag && !SlotDown[j])
				{
					LogPress(j, (InputHandle_t)((connectedControllers > 0) ? _pads[0] : default(InputHandle_t)));
				}
				SlotDown[j] = flag;
			}
		}

		private bool PadsChanged(int count)
		{
			bool flag = count != _padCount;
			for (int i = 0; i < count; i++)
			{
				flag |= _lastPads[i] != _pads[i].m_InputHandle;
				_lastPads[i] = _pads[i].m_InputHandle;
			}
			return flag;
		}

		internal EInputActionOrigin? OriginFor(int slot)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (!_initialized || _padCount < 1 || _actions[slot].m_InputDigitalActionHandle == 0L)
			{
				return null;
			}
			if (SteamInput.GetDigitalActionOrigins(_pads[0], _set, _actions[slot], _origins) <= 0)
			{
				return null;
			}
			return _origins[0];
		}

		private void ResolveHandles()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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)
			if (_set.m_InputActionSetHandle == 0L)
			{
				_set = SteamInput.GetActionSetHandle("Default");
			}
			for (int i = 0; i < 12; i++)
			{
				if (_actions[i].m_InputDigitalActionHandle == 0L)
				{
					_actions[i] = SteamInput.GetDigitalActionHandle(ActionNames[i]);
				}
			}
		}

		private static string[] BuildActionNames()
		{
			string[] array = new string[12];
			for (int i = 0; i < 12; i++)
			{
				array[i] = $"extra_{i + 1}";
			}
			return array;
		}

		private void LogPads()
		{
			//IL_0052: 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)
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[extra] {_padCount} controller(s) connected");
			for (int i = 0; i < _padCount; i++)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[extra] pad{i} handle={_pads[i].m_InputHandle} type={SteamInput.GetInputTypeForHandle(_pads[i])}");
			}
		}

		private void LogPress(int s, InputHandle_t pad)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			int digitalActionOrigins = SteamInput.GetDigitalActionOrigins(pad, _set, _actions[s], _origins);
			string text = "";
			for (int i = 0; i < digitalActionOrigins; i++)
			{
				text = text + " '" + SteamInput.GetStringForActionOrigin(_origins[i]) + "'";
			}
			((BaseUnityPlugin)this).Logger.LogDebug((object)$"[extra] extra_{s + 1} DOWN ->{text} (InControl {ControlFor(s)})");
		}
	}
	[HarmonyPatch]
	internal static class Glyphs
	{
		private static readonly Dictionary<EInputActionOrigin, Sprite> Cache = new Dictionary<EInputActionOrigin, Sprite>();

		private static readonly Dictionary<EInputActionOrigin, float> RetryAt = new Dictionary<EInputActionOrigin, float>();

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIButtonSkins), "GetButtonSkinFor", new Type[] { typeof(InputControlType) })]
		private static void UseSteamGlyph(UIButtonSkins __instance, InputControlType inputControlType, ButtonSkin __result)
		{
			//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)
			//IL_003e: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			int num = ExtraButtonSupportPlugin.SlotFor(inputControlType);
			if (num < 0)
			{
				return;
			}
			EInputActionOrigin? val;
			try
			{
				val = ExtraButtonSupportPlugin.Instance?.OriginFor(num);
			}
			catch (Exception)
			{
				return;
			}
			if (!val.HasValue)
			{
				return;
			}
			EInputActionOrigin valueOrDefault = val.GetValueOrDefault();
			if (!Cache.TryGetValue(valueOrDefault, out Sprite value))
			{
				if (RetryAt.TryGetValue(valueOrDefault, out var value2) && Time.unscaledTime < value2)
				{
					return;
				}
				value = GlyphHelpers.Load(valueOrDefault, __instance.blankKey);
				if ((Object)(object)value == (Object)null)
				{
					RetryAt[valueOrDefault] = Time.unscaledTime + 10f;
					return;
				}
				Cache[valueOrDefault] = value;
			}
			__result.sprite = value;
		}
	}
	internal static class GlyphHelpers
	{
		private static readonly HashSet<EInputActionOrigin> Reported = new HashSet<EInputActionOrigin>();

		internal static Sprite? Load(EInputActionOrigin origin, Sprite reference)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected I4, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = null;
			try
			{
				string glyphPNGForActionOrigin = SteamInput.GetGlyphPNGForActionOrigin(origin, (ESteamInputGlyphSize)2, 0u);
				if (string.IsNullOrEmpty(glyphPNGForActionOrigin) || !File.Exists(glyphPNGForActionOrigin))
				{
					throw new FileNotFoundException("no glyph file '" + glyphPNGForActionOrigin + "'");
				}
				val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(val, File.ReadAllBytes(glyphPNGForActionOrigin)))
				{
					throw new InvalidDataException("can't decode '" + glyphPNGForActionOrigin + "'");
				}
				return Loaded(origin, glyphPNGForActionOrigin, val, reference);
			}
			catch (Exception ex)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				if (Reported.Add(origin))
				{
					ManualLogSource? log = ExtraButtonSupportPlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)$"[extra] glyph for origin {(int)origin} not loaded: {ex.Message}");
					}
				}
				return null;
			}
		}

		private static Sprite Loaded(EInputActionOrigin origin, string path, Texture2D tex, Sprite reference)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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)
			//IL_003f: Expected I4, but got Unknown
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_00c6: 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)
			float num = (float)((Texture)tex).width * reference.pixelsPerUnit;
			Rect rect = reference.rect;
			float num2 = num / ((Rect)(ref rect)).width;
			ManualLogSource? log = ExtraButtonSupportPlugin.Log;
			if (log != null)
			{
				object[] obj = new object[8]
				{
					(int)origin,
					path,
					((Texture)tex).width,
					((Texture)tex).height,
					num2,
					null,
					null,
					null
				};
				rect = reference.rect;
				obj[5] = ((Rect)(ref rect)).width;
				rect = reference.rect;
				obj[6] = ((Rect)(ref rect)).height;
				obj[7] = reference.pixelsPerUnit;
				log.LogInfo((object)string.Format("[extra] glyph {0} {1} {2}x{3} ppu={4} (ref {5}x{6} ppu={7})", obj));
			}
			return Sprite.Create(tex, new Rect(0f, 0f, (float)((Texture)tex).width, (float)((Texture)tex).height), new Vector2(0.5f, 0.5f), num2);
		}
	}
	[HarmonyPatch]
	internal static class MenuRowPatches
	{
		private static readonly FieldRef<MappableControllerButton, PlayerAction> RowAction = AccessTools.FieldRefAccess<MappableControllerButton, PlayerAction>("playerAction");

		private static readonly FieldRef<MappableControllerButton, PlayerAction> ActionToSwap = AccessTools.FieldRefAccess<MappableControllerButton, PlayerAction>("actionToSwap");

		private static readonly FieldRef<MappableControllerButton, BindingSource> BindingToSwap = AccessTools.FieldRefAccess<MappableControllerButton, BindingSource>("bindingToSwap");

		[HarmonyPrefix]
		[HarmonyPatch(typeof(UIManager), "UIGoToRemapControllerMenu")]
		private static void AddToolRows(UIManager __instance)
		{
			try
			{
				MenuRows.Ensure(__instance.uiButtonSkins.mappableControllerButtons);
			}
			catch (Exception arg)
			{
				ManualLogSource? log = ExtraButtonSupportPlugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[extra] tool rows not added: {arg}");
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MappableControllerButton), "OnBindingFound")]
		private static void UnbindInsteadOfSwap(MappableControllerButton __instance)
		{
			PlayerAction val = ActionToSwap.Invoke(__instance);
			if (val != null && (Tools.IsTool(RowAction.Invoke(__instance)) || Tools.IsTool(val)))
			{
				BindingToSwap.Invoke(__instance) = null;
			}
		}
	}
	internal static class MenuRows
	{
		private const string Prefix = "ExtraButtonSupport ";

		private const float RowHeight = 100f;

		internal static void Ensure(RectTransform rows)
		{
			//IL_0061: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Transform)rows).Find("ExtraButtonSupport " + Tools.Names[0]) != (Object)null)
			{
				return;
			}
			MappableControllerButton val = Find(rows, "CastButton");
			MappableControllerButton val2 = Find(rows, "QCastButton");
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				ManualLogSource? log = ExtraButtonSupportPlugin.Log;
				if (log != null)
				{
					log.LogError((object)"[extra] remap rows not found; tool rows not added");
				}
				return;
			}
			rows.anchoredPosition += new Vector2(0f, 100f);
			Navigation navigation = ((Selectable)val).navigation;
			Selectable selectOnDown = ((Navigation)(ref navigation)).selectOnDown;
			MappableControllerButton val3 = Clone(val, 0, 1);
			MappableControllerButton val4 = Clone(val, 2, 2);
			MappableControllerButton val5 = Clone(val2, 1, 1);
			MappableControllerButton val6 = Clone(val2, 3, 2);
			Link((Selectable)(object)val, null, (Selectable?)(object)val3);
			Link((Selectable)(object)val3, (Selectable?)(object)val, (Selectable?)(object)val4, null, (Selectable?)(object)val5);
			Link((Selectable)(object)val4, (Selectable?)(object)val3, selectOnDown, null, (Selectable?)(object)val6);
			Link((Selectable)(object)val2, null, (Selectable?)(object)val5);
			Link((Selectable)(object)val5, (Selectable?)(object)val2, (Selectable?)(object)val6, (Selectable?)(object)val3);
			Link((Selectable)(object)val6, (Selectable?)(object)val5, selectOnDown, (Selectable?)(object)val4);
			if ((Object)(object)selectOnDown != (Object)null)
			{
				Link(selectOnDown, (Selectable?)(object)val4);
			}
			ManualLogSource? log2 = ExtraButtonSupportPlugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)"[extra] added tool rows to Remap Controller screen");
			}
		}

		private static MappableControllerButton? Find(RectTransform rows, string name)
		{
			Transform obj = ((Transform)rows).Find(name);
			if (obj == null)
			{
				return null;
			}
			return ((Component)obj).GetComponent<MappableControllerButton>();
		}

		private static MappableControllerButton Clone(MappableControllerButton template, int tool, int rowsBelow)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: 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)
			GameObject val = new GameObject("ExtraButtonSupport holder");
			val.SetActive(false);
			MappableControllerButton val2 = Object.Instantiate<MappableControllerButton>(template, val.transform);
			((Object)val2).name = "ExtraButtonSupport " + Tools.Names[tool];
			val2.actionButtonType = (HeroActionButton)(100 + tool);
			Transform val3 = ((Component)val2).transform.Find("Input Button Text");
			Component[] components = ((Component)val3).GetComponents<Component>();
			foreach (Component val4 in components)
			{
				if (((object)val4).GetType().Name == "AutoLocalizeTextUI")
				{
					Object.DestroyImmediate((Object)(object)val4);
				}
			}
			((Component)val3).GetComponent<Text>().text = Tools.Names[tool];
			RectTransform val5 = (RectTransform)((Component)val2).transform;
			((Transform)val5).SetParent(((Component)template).transform.parent, false);
			val5.anchoredPosition = ((RectTransform)((Component)template).transform).anchoredPosition - new Vector2(0f, 100f * (float)rowsBelow);
			Object.Destroy((Object)(object)val);
			return val2;
		}

		private static void Link(Selectable s, Selectable? upTo = null, Selectable? down = null, Selectable? left = null, Selectable? right = null)
		{
			//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)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			Navigation navigation = s.navigation;
			((Navigation)(ref navigation)).mode = (Mode)4;
			if ((Object)(object)upTo != (Object)null)
			{
				((Navigation)(ref navigation)).selectOnUp = upTo;
			}
			if ((Object)(object)down != (Object)null)
			{
				((Navigation)(ref navigation)).selectOnDown = down;
			}
			if ((Object)(object)left != (Object)null)
			{
				((Navigation)(ref navigation)).selectOnLeft = left;
			}
			if ((Object)(object)right != (Object)null)
			{
				((Navigation)(ref navigation)).selectOnRight = right;
			}
			s.navigation = navigation;
		}
	}
	internal static class Tools
	{
		internal static readonly string[] Names = new string[4] { "Tool Up", "Tool Neutral", "Tool Down", "Scuttle" };

		internal const int ScuttleIndex = 3;

		internal static readonly AttackToolBinding[] Slots = (AttackToolBinding[])(object)new AttackToolBinding[3]
		{
			(AttackToolBinding)1,
			default(AttackToolBinding),
			(AttackToolBinding)2
		};

		internal const int ButtonBase = 100;

		private static HeroActions? _owner;

		private static readonly PlayerAction[] Actions = (PlayerAction[])(object)new PlayerAction[4];

		internal static HeroActions? Owner => _owner;

		internal static PlayerAction[] For(HeroActions heroActions)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (_owner != heroActions)
			{
				for (int i = 0; i < Names.Length; i++)
				{
					Actions[i] = (PlayerAction)(((object)((PlayerActionSet)heroActions).GetPlayerActionByName("ExtraButtonSupport " + Names[i])) ?? ((object)new PlayerAction("ExtraButtonSupport " + Names[i], (PlayerActionSet)(object)heroActions)));
				}
				_owner = heroActions;
			}
			return Actions;
		}

		internal static bool IsTool(PlayerAction? action)
		{
			if (_owner != null && action != null)
			{
				return Array.IndexOf(Actions, action) >= 0;
			}
			return false;
		}

		internal static AttackToolBinding? Held(InputDevice? device)
		{
			if (_owner == null || device == null)
			{
				return null;
			}
			for (int i = 0; i < Slots.Length; i++)
			{
				if (IsHeld(Actions[i], device))
				{
					return Slots[i];
				}
			}
			return null;
		}

		internal static bool ScuttleHeld(InputDevice? device)
		{
			if (_owner != null && device != null && IsHeld(Actions[3], device))
			{
				return ((ToolBase)Gameplay.ScuttleCharmTool).IsEquipped;
			}
			return false;
		}

		private static bool IsHeld(PlayerAction action, InputDevice device)
		{
			ReadOnlyCollection<BindingSource> bindings = action.Bindings;
			for (int i = 0; i < bindings.Count; i++)
			{
				if (bindings[i].GetState(device))
				{
					return true;
				}
			}
			return false;
		}

		internal unsafe static ConfigEntry<InputControlType> Saved(GamepadType pad, int i)
		{
			return ((BaseUnityPlugin)ExtraButtonSupportPlugin.Instance).Config.Bind<InputControlType>("Bindings." + ((object)(*(GamepadType*)(&pad))/*cast due to .constrained prefix*/).ToString(), Names[i].Replace(" ", ""), (InputControlType)0, "Controller button for " + Names[i] + " (set from the in-game Controller remap screen)");
		}
	}
	[HarmonyPatch]
	internal static class ToolActionPatches
	{
		private delegate bool CanThrowToolFn(HeroController hero, ToolItem tool, AttackToolBinding binding, bool reportFailure);

		private static readonly FieldRef<HeroController, ToolItem> WillThrowTool = AccessTools.FieldRefAccess<HeroController, ToolItem>("willThrowTool");

		private static readonly CanThrowToolFn CanThrowTool = AccessTools.MethodDelegate<CanThrowToolFn>(AccessTools.Method(typeof(HeroController), "CanThrowTool", new Type[3]
		{
			typeof(ToolItem),
			typeof(AttackToolBinding),
			typeof(bool)
		}, (Type[])null), (object)null, true);

		private static readonly FieldRef<OneAxisInputControl, InputControlState> ControlState = AccessTools.FieldRefAccess<OneAxisInputControl, InputControlState>("thisState");

		private static bool _wasHeld;

		private static readonly FieldRef<HeroController, bool> IsGameplayScene = AccessTools.FieldRefAccess<HeroController, bool>("isGameplayScene");

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InputHandler), "MapControllerButtons")]
		private static void ApplyToolBindings(InputHandler __instance, GamepadType gamePadType)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			PlayerAction[] array = Tools.For(__instance.inputActions);
			for (int i = 0; i < array.Length; i++)
			{
				array[i].ClearBindings();
				InputControlType value = Tools.Saved(gamePadType, i).Value;
				if ((int)value != 0)
				{
					array[i].AddBinding((BindingSource)new DeviceBindingSource(value));
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InputHandler), "SetupMappableControllerBindingsList")]
		private static void AddToMappable(InputHandler __instance)
		{
			__instance.MappableControllerActions.AddRange(Tools.For(__instance.inputActions));
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InputHandler), "SendButtonBindingsToGameSettings")]
		private static void SaveToolBindings(InputHandler __instance)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			PlayerAction[] array = Tools.For(__instance.inputActions);
			for (int i = 0; i < array.Length; i++)
			{
				Tools.Saved(__instance.activeGamepadType, i).Value = __instance.GetButtonBindingForAction(array[i]);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InputHandler), "ResetDefaultControllerButtonBindings")]
		private static void ResetToolBindings(InputHandler __instance)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < Tools.Names.Length; i++)
			{
				Tools.Saved(__instance.activeGamepadType, i).Value = (InputControlType)0;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InputHandler), "ActionButtonToPlayerAction")]
		private static bool RowToToolAction(InputHandler __instance, HeroActionButton actionButtonType, ref PlayerAction __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Expected I4, but got Unknown
			int num = actionButtonType - 100;
			if (num < 0 || num >= Tools.Names.Length)
			{
				return true;
			}
			__result = Tools.For(__instance.inputActions)[num];
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerAction), "UpdateBindings")]
		private static void DriveVanillaActions(PlayerAction __instance, ulong updateTick, float deltaTime)
		{
			HeroActions owner = Tools.Owner;
			if (owner == null || ((PlayerActionSet)owner).IsListeningForBinding)
			{
				return;
			}
			bool num;
			if (__instance != owner.QuickCast)
			{
				if (__instance != owner.Dash)
				{
					return;
				}
				num = Tools.ScuttleHeld(InputManager.ActiveDevice);
			}
			else
			{
				num = Tools.Held(InputManager.ActiveDevice).HasValue;
			}
			if (num)
			{
				((OneAxisInputControl)__instance).UpdateWithValue(1f, updateTick, deltaTime);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(HeroController), "HeroDashPressed")]
		private static void ScuttleDirection(HeroController __instance, out InputControlState[]? __state)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			HeroActions owner = Tools.Owner;
			if (owner != null && Tools.ScuttleHeld(InputManager.ActiveDevice))
			{
				__state = (InputControlState[]?)(object)new InputControlState[3]
				{
					ControlState.Invoke((OneAxisInputControl)(object)owner.Down),
					ControlState.Invoke((OneAxisInputControl)(object)owner.Left),
					ControlState.Invoke((OneAxisInputControl)(object)owner.Right)
				};
				ControlState.Invoke((OneAxisInputControl)(object)owner.Down) = new InputControlState
				{
					State = true,
					Value = 1f,
					RawValue = 1f
				};
				ControlState.Invoke((OneAxisInputControl)(object)owner.Left) = default(InputControlState);
				ControlState.Invoke((OneAxisInputControl)(object)owner.Right) = default(InputControlState);
			}
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(HeroController), "HeroDashPressed")]
		private static void RestoreDirection(InputControlState[]? __state)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			HeroActions owner = Tools.Owner;
			if (__state != null && owner != null)
			{
				ControlState.Invoke((OneAxisInputControl)(object)owner.Down) = __state[0];
				ControlState.Invoke((OneAxisInputControl)(object)owner.Left) = __state[1];
				ControlState.Invoke((OneAxisInputControl)(object)owner.Right) = __state[2];
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(HeroController), "LookForQueueInput")]
		private static void ToolBindCancelsSprint(HeroController __instance)
		{
			bool hasValue = Tools.Held(InputManager.ActiveDevice).HasValue;
			bool num = hasValue && !_wasHeld;
			_wasHeld = hasValue;
			if (!num || __instance.IsInputBlocked() || __instance.IsPaused() || !IsGameplayScene.Invoke(__instance) || (Object)(object)InteractManager.BlockingInteractable != (Object)null)
			{
				return;
			}
			HeroActions? owner = Tools.Owner;
			if (owner != null && ((PlayerActionSet)owner).IsListeningForBinding)
			{
				return;
			}
			PlayMakerFSM sprintFSM = __instance.sprintFSM;
			if (SprintFsm.Accepts(sprintFSM, "TOOLTHROW") && __instance.GetWillThrowTool(true))
			{
				string activeStateName = sprintFSM.ActiveStateName;
				sprintFSM.SendEvent("TOOLTHROW");
				ManualLogSource? log = ExtraButtonSupportPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("[extra] tool bind interrupted sprint: " + activeStateName + " -> " + sprintFSM.ActiveStateName));
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(HeroController), "GetWillThrowTool")]
		private static bool UseHeldSlot(HeroController __instance, bool reportFailure, ref bool __result)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			AttackToolBinding? val = Tools.Held(InputManager.ActiveDevice);
			if (val.HasValue)
			{
				AttackToolBinding valueOrDefault = val.GetValueOrDefault();
				AttackToolBinding binding = default(AttackToolBinding);
				ToolItem boundAttackTool = ToolItemManager.GetBoundAttackTool(valueOrDefault, (ToolEquippedReadSource)0, ref binding);
				WillThrowTool.Invoke(__instance) = boundAttackTool;
				__result = Object.op_Implicit((Object)(object)boundAttackTool) && CanThrowTool(__instance, boundAttackTool, binding, reportFailure);
				return false;
			}
			return true;
		}
	}
	internal static class SprintFsm
	{
		internal static bool Accepts(PlayMakerFSM fsm, string eventName)
		{
			FsmState activeState = fsm.Fsm.ActiveState;
			FsmTransition[] array = ((activeState != null) ? activeState.Transitions : null) ?? Array.Empty<FsmTransition>();
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i].EventName == eventName)
				{
					return true;
				}
			}
			return false;
		}
	}
}