Decompiled source of Toggle Melee Stance v1.6.0

Toggle Melee Stance.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.InputSystem;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Toggle Melee Stance")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Toggle Melee Stance")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("a7db406a-f689-4a93-87dd-978986c6f891")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ToggleMeleeStance;

[BepInPlugin("kumo.sulfur.toggle_melee_stance", "Toggle Melee Stance", "1.6.0")]
public sealed class Plugin : BaseUnityPlugin
{
	private sealed class ToggleState
	{
		public bool IsToggled;

		public bool AttackInProgress;

		public bool SheatheAfterAttack;

		public bool SuppressMeleeUntilReleased;

		public float NextChargeAttemptTime;

		public bool PendingTapHold;

		public bool LongPressPassThrough;

		public bool WasMeleeHeldLastFrame;

		public float MeleePressStartTime;

		public float LastMaintainTime;

		public bool CompletingMeleeAttack;

		public float LastEquipmentInputTime;

		public WeaponSelectionRequest PendingWeaponSelection;

		public object PendingWeaponSelectionSlot;

		public MeleeKeyMode? AppliedMeleeKeyMode;

		public bool StanceIsLastUsed;

		public object StanceReturnSlot;

		public int StanceExitFrame;
	}

	public enum MeleeKeyMode
	{
		TapToggleHoldQuickMelee,
		TapQuickMeleeHoldToggle,
		PressToggles,
		QuickMeleeChordToggle
	}

	private enum WeaponSelectionRequest
	{
		None,
		Slot,
		Next,
		Previous,
		LastUsed
	}

	private sealed class SafeAnimatorState
	{
		public bool Valid;

		public int FullPathHash;

		public int ShortNameHash;

		public string ClipName;
	}

	public const string PluginGuid = "kumo.sulfur.toggle_melee_stance";

	public const string PluginName = "Toggle Melee Stance";

	public const string PluginVersion = "1.6.0";

	public const string MeleeExpansionGuid = "kumo.sulfur.melee_expansion";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> EnableMod;

	internal static ConfigEntry<bool> FirePerformsMeleeAttack;

	internal static ConfigEntry<bool> ResetMeleeAnimatorBeforeSheathe;

	internal static ConfigEntry<bool> DisableWhenMeleeExpansionDetected;

	internal static ConfigEntry<bool> KeepMeleeStanceAfterExternalWeaponSwitch;

	internal static ConfigEntry<MeleeKeyMode> MeleeInputMode;

	internal static ConfigEntry<bool> EnableTapHoldMeleeKey;

	internal static ConfigEntry<bool> SwapQuickMeleeAndEquipMelee;

	internal static ConfigEntry<float> MeleeToggleTapThreshold;

	internal static ConfigEntry<bool> WeaponSwitchExitsMeleeStance;

	internal static ConfigEntry<float> ReChargeRetryInterval;

	internal static ConfigEntry<bool> LogStateChanges;

	private Harmony harmony;

	private static Type equipmentManagerType;

	private static Type weaponType;

	private static Type interactableType;

	private static Type gameManagerType;

	private const float StanceLivenessWindow = 0.5f;

	private static MethodInfo mHandleAimInput;

	private static MethodInfo mHandleMeleeInput;

	private static MethodInfo mPullTrigger;

	private static MethodInfo mReleaseTrigger;

	private static MethodInfo mChargeBasicMelee;

	private static MethodInfo mUseBasicMelee;

	private static MethodInfo mOnMeleeDone;

	private static MethodInfo mReportMeleeDone;

	private static MethodInfo mIsMeleeCharging;

	private static MethodInfo mChargeMelee;

	private static MethodInfo mSetAlternativeState;

	private static MethodInfo mCanInteract;

	private static MethodInfo mChangeWeapon;

	private static PropertyInfo pWeaponCurrentSlot;

	private static object basicMeleeSlotValue;

	private static PropertyInfo pIsMelee;

	private static PropertyInfo pAnimator;

	private static PropertyInfo pGameManagerInstance;

	private static PropertyInfo pGameManagerEquipmentManager;

	private static FieldInfo fAltFireAction;

	private static FieldInfo fMeleeFireAction;

	private static FieldInfo fMeleeFireActionAlternative;

	private static FieldInfo fSelectLastUsedAction;

	private static FieldInfo fCurrentHoldable;

	private static FieldInfo fEquipmentManager;

	private static FieldInfo fIsInMeleeCharge;

	private static FieldInfo fMeleePressed;

	private static FieldInfo fAlternativeMeleePressed;

	private static FieldInfo fAimingInputHeld;

	private static FieldInfo fMeleeInputCooldown;

	private static FieldInfo fCurrentParries;

	private static MethodInfo mNextWeapon;

	private static MethodInfo mPreviousWeapon;

	private static MethodInfo mSelectLastUsedWeapon;

	private static MethodInfo mInventoryItemUse;

	private static PropertyInfo pWeaponSwitchingPrevented;

	private static PropertyInfo pGamepadUsed;

	private static PropertyInfo pInventoryItemDefinition;

	private static PropertyInfo pInventoryItemUseType;

	private static FieldInfo fItemDefinitionPrefab;

	private static FieldInfo fEquippedItems;

	private static object inventorySlotNoneValue;

	private static object consumableUseTypeValue;

	private static bool changeWeaponSignatureMatches;

	private static readonly ConditionalWeakTable<object, ToggleState> States = new ConditionalWeakTable<object, ToggleState>();

	private static readonly ConditionalWeakTable<object, SafeAnimatorState> SafeAnimatorStates = new ConditionalWeakTable<object, SafeAnimatorState>();

	public static bool IsRuntimeReady
	{
		get
		{
			if (EnableMod != null && equipmentManagerType != null)
			{
				return weaponType != null;
			}
			return false;
		}
	}

	private void Awake()
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Expected O, but got Unknown
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Expected O, but got Unknown
		//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f2: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		EnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, "Enable Toggle Melee Stance.");
		FirePerformsMeleeAttack = ((BaseUnityPlugin)this).Config.Bind<bool>("Melee", "FirePerformsMeleeAttack", true, "When melee stance is toggled on, pressing the normal Fire action performs one melee attack.");
		ReChargeRetryInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Melee", "ReChargeRetryInterval", 0.08f, new ConfigDescription("Seconds between retry attempts when the mod tries to re-enter melee charge after an attack.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.5f), Array.Empty<object>()));
		ResetMeleeAnimatorBeforeSheathe = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "ResetMeleeAnimatorBeforeSheathe", true, "Before sheathing a toggled melee weapon, reset its Animator to the cached safe equip state. This prevents stale idle states from causing a slash-frame flash on the next draw.");
		DisableWhenMeleeExpansionDetected = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "DisableWhenMeleeExpansionDetected", false, "Deprecated. Kept only for old config compatibility. Toggle Melee Stance no longer auto-disables when The Dragonblade is installed, because it is now the shared prerequisite melee stance module.");
		KeepMeleeStanceAfterExternalWeaponSwitch = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "KeepMeleeStanceAfterExternalWeaponSwitch", false, "When another mod changes the current weapon while toggle melee stance is active, keep melee stance instead of exiting it. Default false: exit stance and allow the new weapon to fire normally.");
		MeleeInputMode = ((BaseUnityPlugin)this).Config.Bind<MeleeKeyMode>("Melee", "MeleeInputMode", MeleeKeyMode.TapToggleHoldQuickMelee, "How the melee key works. TapToggleHoldQuickMelee (default): tap to toggle melee stance, hold for the original quick melee. TapQuickMeleeHoldToggle: tap for the original quick melee, hold to toggle melee stance. PressToggles: every press toggles melee stance, with no quick melee. QuickMeleeChordToggle: the melee key works as in the base game, and pressing Fire or the last used weapon key while holding it enters melee stance instead of attacking. In every mode, press the melee key again to leave melee stance.");
		EnableTapHoldMeleeKey = ((BaseUnityPlugin)this).Config.Bind<bool>("Melee", "EnableTapHoldMeleeKey", true, "Deprecated, read once for migration. Replaced by MeleeInputMode. If this is false while MeleeInputMode is at its default, the next start sets MeleeInputMode to PressToggles and resets this entry to true.");
		SwapQuickMeleeAndEquipMelee = ((BaseUnityPlugin)this).Config.Bind<bool>("Melee", "SwapQuickMeleeAndEquipMelee", false, "Deprecated, read once for migration. Replaced by MeleeInputMode. If this is true while MeleeInputMode is at its default and EnableTapHoldMeleeKey is true, the next start sets MeleeInputMode to TapQuickMeleeHoldToggle and resets this entry to false.");
		MeleeToggleTapThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Melee", "MeleeToggleTapThreshold", 0.13f, new ConfigDescription("Used only by the TapToggleHoldQuickMelee and TapQuickMeleeHoldToggle input modes. Maximum press duration treated as a tap. A longer press counts as a hold.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 0.6f), Array.Empty<object>()));
		WeaponSwitchExitsMeleeStance = ((BaseUnityPlugin)this).Config.Bind<bool>("Melee", "WeaponSwitchExitsMeleeStance", true, "When melee stance is on, the weapon selection controls leave it. The weapon slot keys (1-5 by default) switch to that slot. The last used weapon key and weapon cycling with the scroll wheel or gamepad d-pad return to the weapon you held before the stance. However the stance ends, the last used weapon key then takes you back into it, until you switch to another weapon. A slot chosen during a melee attack is applied when the attack finishes. Consumables in slots 3-5 are used without leaving melee stance.");
		LogStateChanges = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogStateChanges", false, "Log toggle melee state changes. Keep false for normal gameplay.");
		MigrateLegacyMeleeKeySettings();
		if (!InitializeReflection())
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"Reflection initialization failed. Mod will not patch.");
			return;
		}
		harmony = new Harmony("kumo.sulfur.toggle_melee_stance");
		Patch(mHandleAimInput, "HandleAimInputPrefix");
		Patch(mHandleMeleeInput, "HandleMeleeInputPrefix");
		Patch(mPullTrigger, "PullTriggerPrefix");
		Patch(mReleaseTrigger, "ReleaseTriggerPrefix");
		Patch(mReportMeleeDone, "ReportMeleeDonePrefix", "ReportMeleeDonePostfix");
		Patch(mChargeMelee, null, "ChargeMeleePostfix");
		if (mCanInteract != null && pGameManagerInstance != null && pGameManagerEquipmentManager != null)
		{
			Patch(mCanInteract, null, "CanInteractPostfix");
		}
		else
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Interaction-in-melee-stance fix disabled: could not resolve Interactable.CanInteract or GameManager equipment access. Item pickup will be blocked while melee stance is active.");
		}
		if (mChangeWeapon != null && pWeaponCurrentSlot != null && basicMeleeSlotValue != null)
		{
			Patch(mChangeWeapon, null, "ChangeWeaponPostfix");
		}
		else
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Melee slot exit tracking disabled: could not resolve EquipmentManager.ChangeWeapon or EquipmentManager.weaponCurrentSlot. A melee attack interrupted by a forced weapon change may leave the stance state stale.");
		}
		if (CanHandleWeaponSlotKeys())
		{
			Patch(mChangeWeapon, "ChangeWeaponPrefix");
		}
		else
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Weapon slot keys will not leave melee stance: could not resolve EquipmentManager.ChangeWeapon(InventorySlot, bool forced, bool navigatedDirectlyTo) or the equipped item members it needs.");
		}
		PatchWeaponSelectionEntry(mNextWeapon, "NextWeaponPrefix", "EquipmentManager.NextWeapon()");
		PatchWeaponSelectionEntry(mPreviousWeapon, "PreviousWeaponPrefix", "EquipmentManager.PreviousWeapon(InventorySlot)");
		PatchWeaponSelectionEntry(mSelectLastUsedWeapon, "SelectLastUsedWeaponPrefix", "EquipmentManager.SelectLastUsedWeapon()");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Toggle Melee Stance loaded.");
	}

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

	private static void MigrateLegacyMeleeKeySettings()
	{
		bool flag = !EnableTapHoldMeleeKey.Value;
		bool value = SwapQuickMeleeAndEquipMelee.Value;
		if (!flag && !value)
		{
			return;
		}
		if (MeleeInputMode.Value == MeleeKeyMode.TapToggleHoldQuickMelee)
		{
			MeleeInputMode.Value = ((!flag) ? MeleeKeyMode.TapQuickMeleeHoldToggle : MeleeKeyMode.PressToggles);
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Migrated EnableTapHoldMeleeKey=" + EnableTapHoldMeleeKey.Value + ", SwapQuickMeleeAndEquipMelee=" + SwapQuickMeleeAndEquipMelee.Value + " to MeleeInputMode=" + MeleeInputMode.Value.ToString() + "."));
			}
		}
		else
		{
			ManualLogSource log2 = Log;
			if (log2 != null)
			{
				log2.LogInfo((object)("Ignored the deprecated EnableTapHoldMeleeKey / SwapQuickMeleeAndEquipMelee values because MeleeInputMode is set (" + MeleeInputMode.Value.ToString() + ")."));
			}
		}
		EnableTapHoldMeleeKey.Value = true;
		SwapQuickMeleeAndEquipMelee.Value = false;
	}

	private static MeleeKeyMode GetMeleeKeyMode()
	{
		if (MeleeInputMode == null)
		{
			return MeleeKeyMode.TapToggleHoldQuickMelee;
		}
		MeleeKeyMode value = MeleeInputMode.Value;
		if ((uint)(value - 1) <= 2u)
		{
			return MeleeInputMode.Value;
		}
		return MeleeKeyMode.TapToggleHoldQuickMelee;
	}

	private static bool InitializeReflection()
	{
		equipmentManagerType = AccessTools.TypeByName("PerfectRandom.Sulfur.Core.Items.EquipmentManager");
		weaponType = AccessTools.TypeByName("PerfectRandom.Sulfur.Core.Weapons.Weapon");
		if (equipmentManagerType == null)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogError((object)"Could not find EquipmentManager type.");
			}
			return false;
		}
		if (weaponType == null)
		{
			ManualLogSource log2 = Log;
			if (log2 != null)
			{
				log2.LogError((object)"Could not find Weapon type.");
			}
			return false;
		}
		mHandleAimInput = AccessTools.Method(equipmentManagerType, "HandleAimInput", new Type[1] { typeof(bool) }, (Type[])null);
		mHandleMeleeInput = AccessTools.Method(equipmentManagerType, "HandleMeleeInput", new Type[1] { typeof(bool) }, (Type[])null);
		mPullTrigger = AccessTools.Method(equipmentManagerType, "PullTrigger", (Type[])null, (Type[])null);
		mReleaseTrigger = AccessTools.Method(equipmentManagerType, "ReleaseTrigger", (Type[])null, (Type[])null);
		mChargeBasicMelee = AccessTools.Method(equipmentManagerType, "ChargeBasicMelee", (Type[])null, (Type[])null);
		mUseBasicMelee = AccessTools.Method(equipmentManagerType, "UseBasicMelee", (Type[])null, (Type[])null);
		mOnMeleeDone = AccessTools.Method(equipmentManagerType, "OnMeleeDone", (Type[])null, (Type[])null);
		mReportMeleeDone = AccessTools.Method(weaponType, "ReportMeleeDone", (Type[])null, (Type[])null);
		mIsMeleeCharging = AccessTools.Method(weaponType, "IsMeleeCharging", (Type[])null, (Type[])null);
		mChargeMelee = AccessTools.Method(weaponType, "ChargeMelee", new Type[1] { typeof(bool) }, (Type[])null);
		mSetAlternativeState = AccessTools.Method(weaponType, "SetAlternativeState", new Type[1] { typeof(int) }, (Type[])null);
		pIsMelee = AccessTools.Property(weaponType, "IsMelee");
		pAnimator = FindPropertyRecursive(weaponType, "Animator");
		fAltFireAction = FindFieldRecursive(equipmentManagerType, "altFireAction");
		fMeleeFireAction = FindFieldRecursive(equipmentManagerType, "meleeFireAction");
		fMeleeFireActionAlternative = FindFieldRecursive(equipmentManagerType, "meleeFireActionAlternative");
		fSelectLastUsedAction = FindFieldRecursive(equipmentManagerType, "selectLastUsedAction");
		if (fSelectLastUsedAction != null && !typeof(InputAction).IsAssignableFrom(fSelectLastUsedAction.FieldType))
		{
			fSelectLastUsedAction = null;
		}
		fCurrentHoldable = FindFieldRecursive(equipmentManagerType, "currentHoldable");
		fEquipmentManager = FindFieldRecursive(weaponType, "equipmentManager");
		fIsInMeleeCharge = FindFieldRecursive(equipmentManagerType, "<isInMeleeCharge>k__BackingField", "isInMeleeCharge");
		fMeleePressed = FindFieldRecursive(equipmentManagerType, "<meleePressed>k__BackingField", "meleePressed");
		fAlternativeMeleePressed = FindFieldRecursive(equipmentManagerType, "<alternativeMeleePressed>k__BackingField", "alternativeMeleePressed");
		fAimingInputHeld = FindFieldRecursive(equipmentManagerType, "<AimingInputHeld>k__BackingField", "AimingInputHeld");
		fMeleeInputCooldown = FindFieldRecursive(equipmentManagerType, "meleeInputCooldown");
		fCurrentParries = FindFieldRecursive(weaponType, "currentParries");
		interactableType = AccessTools.TypeByName("PerfectRandom.Sulfur.Core.World.Interactable");
		gameManagerType = AccessTools.TypeByName("PerfectRandom.Sulfur.Core.GameManager");
		if (interactableType != null)
		{
			mCanInteract = AccessTools.Method(interactableType, "CanInteract", Type.EmptyTypes, (Type[])null);
		}
		if (gameManagerType != null)
		{
			pGameManagerInstance = FindPropertyRecursive(gameManagerType, "Instance");
			pGameManagerEquipmentManager = FindPropertyRecursive(gameManagerType, "EquipmentManager");
		}
		mChangeWeapon = AccessTools.Method(equipmentManagerType, "ChangeWeapon", (Type[])null, (Type[])null);
		pWeaponCurrentSlot = FindPropertyRecursive(equipmentManagerType, "weaponCurrentSlot");
		if (pWeaponCurrentSlot != null && pWeaponCurrentSlot.PropertyType.IsEnum)
		{
			try
			{
				basicMeleeSlotValue = Enum.Parse(pWeaponCurrentSlot.PropertyType, "BasicMelee");
			}
			catch (ArgumentException)
			{
				basicMeleeSlotValue = null;
			}
		}
		ResolveWeaponSelectionMembers();
		if (Require(mHandleAimInput, "EquipmentManager.HandleAimInput(bool)") && Require(mHandleMeleeInput, "EquipmentManager.HandleMeleeInput(bool)") && Require(mPullTrigger, "EquipmentManager.PullTrigger()") && Require(mReleaseTrigger, "EquipmentManager.ReleaseTrigger()") && RequireArity(mChargeBasicMelee, 0, "EquipmentManager.ChargeBasicMelee()") && RequireArity(mUseBasicMelee, 0, "EquipmentManager.UseBasicMelee()") && RequireArity(mOnMeleeDone, 0, "EquipmentManager.OnMeleeDone()") && Require(mReportMeleeDone, "Weapon.ReportMeleeDone()") && RequireArity(mIsMeleeCharging, 0, "Weapon.IsMeleeCharging()") && Require(mChargeMelee, "Weapon.ChargeMelee(bool)") && Require(mSetAlternativeState, "Weapon.SetAlternativeState(int)") && Require(pIsMelee, "Weapon.IsMelee") && Require(pAnimator, "Holdable.Animator") && Require(fAltFireAction, "EquipmentManager.altFireAction") && Require(fMeleeFireAction, "EquipmentManager.meleeFireAction") && Require(fMeleeFireActionAlternative, "EquipmentManager.meleeFireActionAlternative") && Require(fCurrentHoldable, "EquipmentManager.currentHoldable") && Require(fEquipmentManager, "Weapon.equipmentManager") && Require(fIsInMeleeCharge, "EquipmentManager.isInMeleeCharge") && Require(fMeleePressed, "EquipmentManager.meleePressed") && Require(fAlternativeMeleePressed, "EquipmentManager.alternativeMeleePressed") && Require(fAimingInputHeld, "EquipmentManager.AimingInputHeld"))
		{
			return Require(fMeleeInputCooldown, "EquipmentManager.meleeInputCooldown");
		}
		return false;
	}

	private static bool Require(MemberInfo member, string name)
	{
		if (member != null)
		{
			return true;
		}
		ManualLogSource log = Log;
		if (log != null)
		{
			log.LogError((object)("Missing required member: " + name));
		}
		return false;
	}

	private static bool RequireArity(MethodInfo method, int parameterCount, string name)
	{
		if (!Require(method, name))
		{
			return false;
		}
		int num = method.GetParameters().Length;
		if (num == parameterCount)
		{
			return true;
		}
		ManualLogSource log = Log;
		if (log != null)
		{
			log.LogError((object)("Incompatible signature for required member: " + name + " (expected " + parameterCount + " parameter(s), the game method has " + num + ")"));
		}
		return false;
	}

	private static void ResolveWeaponSelectionMembers()
	{
		if (pWeaponCurrentSlot == null || !pWeaponCurrentSlot.PropertyType.IsEnum)
		{
			return;
		}
		Type propertyType = pWeaponCurrentSlot.PropertyType;
		inventorySlotNoneValue = ParseEnumOrNull(propertyType, "None");
		changeWeaponSignatureMatches = HasParameterTypes(mChangeWeapon, propertyType, typeof(bool), typeof(bool)) && mChangeWeapon.GetParameters()[1].Name == "forced" && mChangeWeapon.GetParameters()[2].Name == "navigatedDirectlyTo";
		mNextWeapon = AccessTools.Method(equipmentManagerType, "NextWeapon", Type.EmptyTypes, (Type[])null);
		mPreviousWeapon = AccessTools.Method(equipmentManagerType, "PreviousWeapon", new Type[1] { propertyType }, (Type[])null);
		mSelectLastUsedWeapon = AccessTools.Method(equipmentManagerType, "SelectLastUsedWeapon", Type.EmptyTypes, (Type[])null);
		pWeaponSwitchingPrevented = FindPropertyRecursive(equipmentManagerType, "weaponSwitchingPrevented");
		pGamepadUsed = FindPropertyRecursive(equipmentManagerType, "GamepadUsed");
		if (pWeaponSwitchingPrevented != null && pWeaponSwitchingPrevented.PropertyType != typeof(bool))
		{
			pWeaponSwitchingPrevented = null;
		}
		if (pGamepadUsed != null && pGamepadUsed.PropertyType != typeof(bool))
		{
			pGamepadUsed = null;
		}
		fEquippedItems = FindFieldRecursive(equipmentManagerType, "equippedItems");
		Type[] array = ((fEquippedItems != null && fEquippedItems.FieldType.IsGenericType) ? fEquippedItems.FieldType.GetGenericArguments() : null);
		if (array == null || array.Length != 2 || array[0] != propertyType || !typeof(IDictionary).IsAssignableFrom(fEquippedItems.FieldType))
		{
			fEquippedItems = null;
			return;
		}
		Type type = array[1];
		mInventoryItemUse = AccessTools.Method(type, "Use", new Type[1] { typeof(bool) }, (Type[])null);
		pInventoryItemDefinition = FindPropertyRecursive(type, "itemDefinition");
		pInventoryItemUseType = FindPropertyRecursive(type, "UseType");
		if (pInventoryItemDefinition != null)
		{
			fItemDefinitionPrefab = FindFieldRecursive(pInventoryItemDefinition.PropertyType, "prefab");
		}
		if (fItemDefinitionPrefab != null && !typeof(Object).IsAssignableFrom(fItemDefinitionPrefab.FieldType))
		{
			fItemDefinitionPrefab = null;
		}
		if (pInventoryItemUseType != null && pInventoryItemUseType.PropertyType.IsEnum)
		{
			consumableUseTypeValue = ParseEnumOrNull(pInventoryItemUseType.PropertyType, "Consumable");
		}
	}

	private static object ParseEnumOrNull(Type enumType, string name)
	{
		try
		{
			return Enum.Parse(enumType, name);
		}
		catch (ArgumentException)
		{
			return null;
		}
	}

	private static bool HasParameterTypes(MethodInfo method, params Type[] parameterTypes)
	{
		if (method == null)
		{
			return false;
		}
		ParameterInfo[] parameters = method.GetParameters();
		if (parameters.Length != parameterTypes.Length)
		{
			return false;
		}
		for (int i = 0; i < parameters.Length; i++)
		{
			if (parameters[i].ParameterType != parameterTypes[i])
			{
				return false;
			}
		}
		return true;
	}

	private static bool IsWeaponSelectionBaseResolved()
	{
		if (pWeaponCurrentSlot != null && basicMeleeSlotValue != null)
		{
			return inventorySlotNoneValue != null;
		}
		return false;
	}

	private static bool CanHandleWeaponSlotKeys()
	{
		if (IsWeaponSelectionBaseResolved() && changeWeaponSignatureMatches && fEquippedItems != null && pInventoryItemDefinition != null && fItemDefinitionPrefab != null && pInventoryItemUseType != null && consumableUseTypeValue != null && mInventoryItemUse != null && pGamepadUsed != null)
		{
			return pWeaponSwitchingPrevented != null;
		}
		return false;
	}

	private void PatchWeaponSelectionEntry(MethodInfo original, string prefix, string name)
	{
		if (original != null && IsWeaponSelectionBaseResolved())
		{
			Patch(original, prefix);
		}
		else
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Weapon selection through " + name + " will not leave melee stance: the method or the slot members it needs could not be resolved."));
		}
	}

	private void Patch(MethodInfo original, string prefix = null, string postfix = null)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Expected O, but got Unknown
		HarmonyMethod val = null;
		HarmonyMethod val2 = null;
		if (!string.IsNullOrEmpty(prefix))
		{
			val = new HarmonyMethod(AccessTools.Method(typeof(Plugin), prefix, (Type[])null, (Type[])null));
		}
		if (!string.IsNullOrEmpty(postfix))
		{
			val2 = new HarmonyMethod(AccessTools.Method(typeof(Plugin), postfix, (Type[])null, (Type[])null));
		}
		harmony.Patch((MethodBase)original, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static FieldInfo FindFieldRecursive(Type type, params string[] names)
	{
		Type type2 = type;
		while (type2 != null)
		{
			foreach (string text in names)
			{
				FieldInfo fieldInfo = AccessTools.Field(type2, text);
				if (fieldInfo != null)
				{
					return fieldInfo;
				}
			}
			type2 = type2.BaseType;
		}
		return null;
	}

	private static PropertyInfo FindPropertyRecursive(Type type, string name)
	{
		Type type2 = type;
		while (type2 != null)
		{
			PropertyInfo propertyInfo = AccessTools.Property(type2, name);
			if (propertyInfo != null)
			{
				return propertyInfo;
			}
			type2 = type2.BaseType;
		}
		return null;
	}

	private static ToggleState GetState(object equipmentManager)
	{
		return States.GetValue(equipmentManager, (object _) => new ToggleState());
	}

	public static bool IsMeleeStanceActive(object equipmentManager)
	{
		if (equipmentManager == null || !IsRuntimeReady || !IsModActive())
		{
			return false;
		}
		return GetState(equipmentManager)?.IsToggled ?? false;
	}

	public static bool IsAttackInProgress(object equipmentManager)
	{
		if (equipmentManager == null || !IsRuntimeReady || !IsModActive())
		{
			return false;
		}
		return GetState(equipmentManager)?.AttackInProgress ?? false;
	}

	public static bool IsSheatheAfterAttack(object equipmentManager)
	{
		if (equipmentManager == null || !IsRuntimeReady || !IsModActive())
		{
			return false;
		}
		return GetState(equipmentManager)?.SheatheAfterAttack ?? false;
	}

	public static bool IsMeleeChargeActive(object equipmentManager)
	{
		if (equipmentManager == null || !IsRuntimeReady || !IsModActive())
		{
			return false;
		}
		return IsInMeleeCharge(equipmentManager);
	}

	public static object GetCurrentHoldableForExternal(object equipmentManager)
	{
		if (equipmentManager == null || !IsRuntimeReady)
		{
			return null;
		}
		return GetCurrentHoldable(equipmentManager);
	}

	public static bool IsCurrentHoldableMeleeForExternal(object equipmentManager)
	{
		return IsMeleeWeapon(GetCurrentHoldableForExternal(equipmentManager));
	}

	private static bool IsModActive()
	{
		if (EnableMod != null)
		{
			return EnableMod.Value;
		}
		return false;
	}

	private static void HandleAimInputPrefix(object __instance, ref bool holdingMeleeAction)
	{
		if (IsModActive() && GetState(__instance).IsToggled)
		{
			holdingMeleeAction = true;
		}
	}

	private static bool HandleMeleeInputPrefix(object __instance, bool holdingMeleeAction)
	{
		if (!IsModActive())
		{
			return true;
		}
		ToggleState state = GetState(__instance);
		state.LastEquipmentInputTime = Time.time;
		if (state.IsToggled)
		{
			state.LastMaintainTime = Time.time;
		}
		MeleeKeyMode meleeKeyMode = GetMeleeKeyMode();
		if (state.AppliedMeleeKeyMode != meleeKeyMode)
		{
			state.AppliedMeleeKeyMode = meleeKeyMode;
			ResetTapHoldTracking(state, holdingMeleeAction || IsMeleeHeld(__instance));
		}
		if (state.SuppressMeleeUntilReleased)
		{
			if (state.WasMeleeHeldLastFrame = holdingMeleeAction || IsMeleeHeld(__instance))
			{
				return false;
			}
			state.SuppressMeleeUntilReleased = false;
			if (LogStateChanges.Value)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)"Melee input released after manual sheathe. Input suppression cleared.");
				}
			}
			return false;
		}
		if (!state.IsToggled && IsAimingInputHeld(__instance) && holdingMeleeAction)
		{
			return true;
		}
		if (!state.IsToggled && IsMeleeInputCoolingDown(__instance))
		{
			return true;
		}
		if (!state.IsToggled && meleeKeyMode != MeleeKeyMode.PressToggles)
		{
			bool num;
			bool prefixResult;
			switch (meleeKeyMode)
			{
			case MeleeKeyMode.QuickMeleeChordToggle:
				return true;
			default:
				num = HandleTapHoldMeleeInput(__instance, state, holdingMeleeAction, out prefixResult);
				break;
			case MeleeKeyMode.TapQuickMeleeHoldToggle:
				num = HandleTapHoldMeleeInputSwapped(__instance, state, holdingMeleeAction, out prefixResult);
				break;
			}
			if (num)
			{
				return prefixResult;
			}
		}
		else if (WasMeleePressedThisFrame(__instance))
		{
			if (!state.IsToggled)
			{
				ToggleOn(__instance, state);
				return false;
			}
			ToggleOff(__instance, state);
			return false;
		}
		if (state.IsToggled)
		{
			if (WasMeleePressedThisFrame(__instance))
			{
				ToggleOff(__instance, state);
				return false;
			}
			MaintainToggledMelee(__instance, state);
			return false;
		}
		return true;
	}

	private static bool TryEnterStanceFromChord(object equipmentManager, string source)
	{
		if (!IsModActive() || equipmentManager == null)
		{
			return false;
		}
		if (GetMeleeKeyMode() != MeleeKeyMode.QuickMeleeChordToggle)
		{
			return false;
		}
		ToggleState state = GetState(equipmentManager);
		if (state.IsToggled || state.AttackInProgress || state.SheatheAfterAttack || state.SuppressMeleeUntilReleased)
		{
			return false;
		}
		if (Time.time - state.LastEquipmentInputTime > 0.5f)
		{
			return false;
		}
		if (!IsMeleeHeld(equipmentManager) || !GetBoolField(fMeleePressed, equipmentManager) || !IsInMeleeCharge(equipmentManager) || !IsBasicMeleeSlotSelected(equipmentManager))
		{
			return false;
		}
		object currentHoldable = GetCurrentHoldable(equipmentManager);
		if (!IsMeleeWeapon(currentHoldable) || !IsMeleeCharging(currentHoldable))
		{
			return false;
		}
		if (LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Melee key held with " + source + ". Quick melee charge becomes melee stance."));
			}
		}
		ToggleOn(equipmentManager, state);
		return true;
	}

	private static void ResetTapHoldTracking(ToggleState state, bool meleeHeld)
	{
		state.PendingTapHold = false;
		state.LongPressPassThrough = false;
		state.MeleePressStartTime = 0f;
		state.WasMeleeHeldLastFrame = meleeHeld;
	}

	private static bool PullTriggerPrefix(object __instance)
	{
		if (!IsModActive())
		{
			return true;
		}
		ToggleState state = GetState(__instance);
		if (!state.IsToggled && TryEnterStanceFromChord(__instance, "Fire"))
		{
			return false;
		}
		if (!state.IsToggled)
		{
			return true;
		}
		if (ExitToggledStateIfExternalNonMeleeHoldable(__instance, state, "PullTrigger"))
		{
			return true;
		}
		if (!FirePerformsMeleeAttack.Value)
		{
			return false;
		}
		object currentHoldable = GetCurrentHoldable(__instance);
		if (!IsMeleeWeapon(currentHoldable))
		{
			MaintainToggledMelee(__instance, state);
			return false;
		}
		if (!IsMeleeCharging(currentHoldable))
		{
			MaintainToggledMelee(__instance, state);
			return false;
		}
		if (state.AttackInProgress)
		{
			return false;
		}
		state.AttackInProgress = true;
		state.SheatheAfterAttack = false;
		state.SuppressMeleeUntilReleased = false;
		if (LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)"Fire action converted to melee attack.");
			}
		}
		InvokeUseBasicMelee(__instance);
		return false;
	}

	private static bool ReleaseTriggerPrefix(object __instance)
	{
		if (!IsModActive())
		{
			return true;
		}
		ToggleState state = GetState(__instance);
		if (!state.IsToggled && !state.AttackInProgress && !state.SheatheAfterAttack)
		{
			return true;
		}
		if (!IsMeleeWeapon(GetCurrentHoldable(__instance)))
		{
			return true;
		}
		return false;
	}

	private static void ReportMeleeDonePrefix(object __instance)
	{
		if (!IsModActive())
		{
			return;
		}
		object equipmentManagerFromWeapon = GetEquipmentManagerFromWeapon(__instance);
		if (equipmentManagerFromWeapon != null)
		{
			ToggleState state = GetState(equipmentManagerFromWeapon);
			if (state.IsToggled || state.AttackInProgress || state.SheatheAfterAttack)
			{
				state.CompletingMeleeAttack = true;
				PrepareMeleeAnimatorForFutureDraw(__instance);
			}
		}
	}

	private static void ReportMeleeDonePostfix(object __instance)
	{
		if (!IsModActive())
		{
			return;
		}
		object equipmentManagerFromWeapon = GetEquipmentManagerFromWeapon(__instance);
		if (equipmentManagerFromWeapon == null)
		{
			return;
		}
		ToggleState state = GetState(equipmentManagerFromWeapon);
		state.CompletingMeleeAttack = false;
		if (state.SheatheAfterAttack)
		{
			state.AttackInProgress = false;
			state.SheatheAfterAttack = false;
			state.IsToggled = false;
			state.SuppressMeleeUntilReleased = true;
			state.NextChargeAttemptTime = 0f;
			state.PendingTapHold = false;
			state.LongPressPassThrough = false;
			state.WasMeleeHeldLastFrame = false;
			state.MeleePressStartTime = 0f;
			if (LogStateChanges.Value)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)"Melee attack finished. Staying sheathed.");
				}
			}
			RememberStanceAsLastUsed(equipmentManagerFromWeapon, state);
			ReplayPendingWeaponSelection(equipmentManagerFromWeapon, state);
			return;
		}
		if (!state.IsToggled)
		{
			state.AttackInProgress = false;
			state.NextChargeAttemptTime = 0f;
			return;
		}
		state.AttackInProgress = false;
		state.NextChargeAttemptTime = Time.time + ClampRetryInterval();
		state.PendingTapHold = false;
		state.LongPressPassThrough = false;
		state.WasMeleeHeldLastFrame = false;
		state.MeleePressStartTime = 0f;
		if (LogStateChanges.Value)
		{
			ManualLogSource log2 = Log;
			if (log2 != null)
			{
				log2.LogInfo((object)"Melee attack finished. Re-entering toggled melee stance.");
			}
		}
		InvokeChargeBasicMelee(equipmentManagerFromWeapon);
	}

	private static void ChargeMeleePostfix(object __instance, bool state)
	{
		if (IsModActive() && state)
		{
			CacheSafeMeleeAnimatorStateIfUseful(__instance, "ChargeMelee(true)");
		}
	}

	private static void ChangeWeaponPostfix(object __instance)
	{
		if (!IsModActive() || __instance == null || !States.TryGetValue(__instance, out var value) || value == null)
		{
			return;
		}
		if (value.StanceIsLastUsed)
		{
			if (Time.frameCount == value.StanceExitFrame && !IsBasicMeleeSlotSelected(__instance))
			{
				value.StanceReturnSlot = pWeaponCurrentSlot.GetValue(__instance, null);
			}
			else if (!IsStanceReturnSlotSelected(__instance, value))
			{
				ClearStanceAsLastUsed(value);
			}
		}
		if ((value.AttackInProgress || value.SheatheAfterAttack) && !value.CompletingMeleeAttack && !IsBasicMeleeSlotSelected(__instance))
		{
			AbandonInterruptedMeleeAttack(__instance, value);
		}
	}

	private static bool IsBasicMeleeSlotSelected(object equipmentManager)
	{
		if (pWeaponCurrentSlot == null || basicMeleeSlotValue == null || equipmentManager == null)
		{
			return false;
		}
		object value = pWeaponCurrentSlot.GetValue(equipmentManager, null);
		return basicMeleeSlotValue.Equals(value);
	}

	private static void AbandonInterruptedMeleeAttack(object equipmentManager, ToggleState state)
	{
		bool sheatheAfterAttack = state.SheatheAfterAttack;
		state.AttackInProgress = false;
		state.SheatheAfterAttack = false;
		state.PendingTapHold = false;
		state.LongPressPassThrough = false;
		state.WasMeleeHeldLastFrame = false;
		state.MeleePressStartTime = 0f;
		if (sheatheAfterAttack)
		{
			state.IsToggled = false;
			state.SuppressMeleeUntilReleased = true;
			state.NextChargeAttemptTime = 0f;
			RememberStanceAsLastUsed(equipmentManager, state);
		}
		else if (state.IsToggled)
		{
			state.NextChargeAttemptTime = Time.time + ClampRetryInterval();
		}
		else
		{
			state.NextChargeAttemptTime = 0f;
		}
		if (LogStateChanges != null && LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Melee attack interrupted by a weapon change before it finished. " + (sheatheAfterAttack ? "Staying sheathed." : (state.IsToggled ? "Toggle melee stays ON and will re-enter the melee charge." : "Attack state cleared.")) + " slot=" + ((pWeaponCurrentSlot != null) ? pWeaponCurrentSlot.GetValue(equipmentManager, null) : null)));
			}
		}
	}

	private static void ChangeWeaponPrefix(object __instance, object[] __args, bool forced, bool navigatedDirectlyTo)
	{
		if (!forced && navigatedDirectlyTo && __args != null && __args.Length != 0)
		{
			HandleWeaponSelectionRequest(__instance, WeaponSelectionRequest.Slot, __args[0], "slot key");
		}
	}

	private static bool NextWeaponPrefix(object __instance)
	{
		return !HandleWeaponSelectionRequest(__instance, WeaponSelectionRequest.Next, null, "next weapon");
	}

	private static bool PreviousWeaponPrefix(object __instance, object[] __args)
	{
		if (__args == null || __args.Length == 0 || !inventorySlotNoneValue.Equals(__args[0]))
		{
			return true;
		}
		return !HandleWeaponSelectionRequest(__instance, WeaponSelectionRequest.Previous, null, "previous weapon");
	}

	private static bool SelectLastUsedWeaponPrefix(object __instance)
	{
		if (TryEnterStanceFromChord(__instance, "last used weapon key"))
		{
			return false;
		}
		if (TryReturnToStance(__instance))
		{
			return false;
		}
		return !HandleWeaponSelectionRequest(__instance, WeaponSelectionRequest.LastUsed, null, "last used weapon");
	}

	private static bool HandleWeaponSelectionRequest(object equipmentManager, WeaponSelectionRequest request, object slot, string source)
	{
		if (!IsModActive() || WeaponSwitchExitsMeleeStance == null || !WeaponSwitchExitsMeleeStance.Value || equipmentManager == null)
		{
			return false;
		}
		if (!States.TryGetValue(equipmentManager, out var value) || value == null)
		{
			return false;
		}
		if (value.CompletingMeleeAttack)
		{
			return false;
		}
		bool flag = !value.IsToggled && value.SheatheAfterAttack && value.AttackInProgress;
		if (!value.IsToggled && !flag)
		{
			return false;
		}
		if (Time.time - value.LastEquipmentInputTime > 0.5f)
		{
			return false;
		}
		bool flag2 = request != WeaponSelectionRequest.Slot;
		if (request == WeaponSelectionRequest.Slot)
		{
			if (IsDirectConsumableUse(equipmentManager, slot))
			{
				UseConsumableInStance(equipmentManager, slot);
				return false;
			}
			if (!IsSlotSelectableByChangeWeapon(equipmentManager, slot))
			{
				return false;
			}
		}
		if (!IsBasicMeleeSlotSelected(equipmentManager))
		{
			ExitStanceWithoutMeleeWeapon(equipmentManager, value, source);
			return flag2;
		}
		if (flag)
		{
			if (flag2)
			{
				ClearPendingWeaponSelection(value);
				return true;
			}
			SetPendingWeaponSelection(value, request, slot, source);
			return false;
		}
		if (value.AttackInProgress)
		{
			ToggleOff(equipmentManager, value);
			if (flag2)
			{
				return true;
			}
			SetPendingWeaponSelection(value, request, slot, source);
			return false;
		}
		if (!IsInMeleeCharge(equipmentManager))
		{
			return false;
		}
		if (LogStateChanges != null && LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Weapon selected in melee stance (" + source + "). Leaving melee stance" + (flag2 ? " and returning to the weapon from before it." : (". slot=" + slot))));
			}
		}
		ToggleOff(equipmentManager, value);
		if (flag2)
		{
			return !IsBasicMeleeSlotSelected(equipmentManager);
		}
		return false;
	}

	private static bool IsDirectConsumableUse(object equipmentManager, object slot)
	{
		object equippedItem = GetEquippedItem(equipmentManager, slot);
		if (equippedItem == null)
		{
			return false;
		}
		if (!consumableUseTypeValue.Equals(pInventoryItemUseType.GetValue(equippedItem, null)))
		{
			return false;
		}
		return !GetBoolProperty(pGamepadUsed, equipmentManager);
	}

	private static void UseConsumableInStance(object equipmentManager, object slot)
	{
		if (!GetBoolProperty(pWeaponSwitchingPrevented, equipmentManager) || slot == null || slot.Equals(pWeaponCurrentSlot.GetValue(equipmentManager, null)))
		{
			return;
		}
		object equippedItem = GetEquippedItem(equipmentManager, slot);
		if (equippedItem == null)
		{
			return;
		}
		if (LogStateChanges != null && LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Consumable used from a slot key in melee stance. Melee stance stays ON. slot=" + slot));
			}
		}
		try
		{
			mInventoryItemUse.Invoke(equippedItem, new object[1] { true });
		}
		catch (Exception ex)
		{
			ManualLogSource log2 = Log;
			if (log2 != null)
			{
				log2.LogError((object)("Failed to invoke InventoryItem.Use: " + ex));
			}
		}
	}

	private static bool IsSlotSelectableByChangeWeapon(object equipmentManager, object slot)
	{
		object equippedItem = GetEquippedItem(equipmentManager, slot);
		if (equippedItem == null)
		{
			return false;
		}
		object value = pInventoryItemDefinition.GetValue(equippedItem, null);
		if ((Object)((value != null) ? /*isinst with value type is only supported in some contexts*/: null) != (Object)null)
		{
			return true;
		}
		return consumableUseTypeValue.Equals(pInventoryItemUseType.GetValue(equippedItem, null));
	}

	private static object GetEquippedItem(object equipmentManager, object slot)
	{
		if (fEquippedItems == null || equipmentManager == null || slot == null)
		{
			return null;
		}
		if (!(fEquippedItems.GetValue(equipmentManager) is IDictionary dictionary) || !dictionary.Contains(slot))
		{
			return null;
		}
		return dictionary[slot];
	}

	private static void ExitStanceWithoutMeleeWeapon(object equipmentManager, ToggleState state, string source)
	{
		state.IsToggled = false;
		state.AttackInProgress = false;
		state.SheatheAfterAttack = false;
		state.SuppressMeleeUntilReleased = true;
		state.NextChargeAttemptTime = 0f;
		state.PendingTapHold = false;
		state.LongPressPassThrough = false;
		state.WasMeleeHeldLastFrame = false;
		state.MeleePressStartTime = 0f;
		ClearPendingWeaponSelection(state);
		SetMeleePressed(equipmentManager, value: false);
		SetAlternativeMeleePressed(equipmentManager, value: false);
		RememberStanceAsLastUsed(equipmentManager, state);
		if (LogStateChanges != null && LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Weapon selected in melee stance (" + source + ") while the melee weapon was not drawn. Toggle melee OFF."));
			}
		}
	}

	private static void RememberStanceAsLastUsed(object equipmentManager, ToggleState state)
	{
		if (WeaponSwitchExitsMeleeStance == null || !WeaponSwitchExitsMeleeStance.Value || pWeaponCurrentSlot == null || basicMeleeSlotValue == null || equipmentManager == null)
		{
			ClearStanceAsLastUsed(state);
			return;
		}
		object value = pWeaponCurrentSlot.GetValue(equipmentManager, null);
		if (value == null || basicMeleeSlotValue.Equals(value))
		{
			ClearStanceAsLastUsed(state);
			return;
		}
		state.StanceIsLastUsed = true;
		state.StanceReturnSlot = value;
		state.StanceExitFrame = Time.frameCount;
	}

	private static void ClearStanceAsLastUsed(ToggleState state)
	{
		state.StanceIsLastUsed = false;
		state.StanceReturnSlot = null;
	}

	private static bool IsStanceReturnSlotSelected(object equipmentManager, ToggleState state)
	{
		if (pWeaponCurrentSlot == null || equipmentManager == null || state.StanceReturnSlot == null)
		{
			return false;
		}
		return state.StanceReturnSlot.Equals(pWeaponCurrentSlot.GetValue(equipmentManager, null));
	}

	private static bool TryReturnToStance(object equipmentManager)
	{
		if (!IsModActive() || equipmentManager == null)
		{
			return false;
		}
		if (!States.TryGetValue(equipmentManager, out var value) || value == null || !value.StanceIsLastUsed)
		{
			return false;
		}
		if (WeaponSwitchExitsMeleeStance == null || !WeaponSwitchExitsMeleeStance.Value)
		{
			ClearStanceAsLastUsed(value);
			return false;
		}
		if (value.IsToggled || value.AttackInProgress || value.SheatheAfterAttack || value.CompletingMeleeAttack)
		{
			return false;
		}
		if (Time.time - value.LastEquipmentInputTime > 0.5f)
		{
			return false;
		}
		if (!IsStanceReturnSlotSelected(equipmentManager, value))
		{
			ClearStanceAsLastUsed(value);
			return false;
		}
		if (fEquippedItems != null)
		{
			if (!value.StanceReturnSlot.Equals(inventorySlotNoneValue) && GetEquippedItem(equipmentManager, value.StanceReturnSlot) == null)
			{
				ClearStanceAsLastUsed(value);
				return false;
			}
			if (GetEquippedItem(equipmentManager, basicMeleeSlotValue) == null)
			{
				return false;
			}
		}
		if (IsMeleeHeld(equipmentManager))
		{
			return false;
		}
		if (!WasPerformedThisFrame(GetInputAction(fSelectLastUsedAction, equipmentManager)))
		{
			return false;
		}
		if (LogStateChanges != null && LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)"Last used weapon key after leaving melee stance. Going back into melee stance.");
			}
		}
		ToggleOn(equipmentManager, value);
		return true;
	}

	private static void SetPendingWeaponSelection(ToggleState state, WeaponSelectionRequest request, object slot, string source)
	{
		state.PendingWeaponSelection = request;
		state.PendingWeaponSelectionSlot = slot;
		if (LogStateChanges != null && LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Weapon selected during a melee attack (" + source + "). It will be applied after the attack finishes. slot=" + slot));
			}
		}
	}

	private static void ClearPendingWeaponSelection(ToggleState state)
	{
		state.PendingWeaponSelection = WeaponSelectionRequest.None;
		state.PendingWeaponSelectionSlot = null;
	}

	private static void ReplayPendingWeaponSelection(object equipmentManager, ToggleState state)
	{
		WeaponSelectionRequest pendingWeaponSelection = state.PendingWeaponSelection;
		object pendingWeaponSelectionSlot = state.PendingWeaponSelectionSlot;
		ClearPendingWeaponSelection(state);
		if (pendingWeaponSelection != WeaponSelectionRequest.Slot || WeaponSwitchExitsMeleeStance == null || !WeaponSwitchExitsMeleeStance.Value)
		{
			return;
		}
		if (LogStateChanges != null && LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Applying the weapon selection made during the melee attack: slot=" + pendingWeaponSelectionSlot));
			}
		}
		try
		{
			mChangeWeapon.Invoke(equipmentManager, new object[3] { pendingWeaponSelectionSlot, false, true });
		}
		catch (Exception ex)
		{
			ManualLogSource log2 = Log;
			if (log2 != null)
			{
				log2.LogError((object)("Failed to apply the weapon selection made during the melee attack: " + ex));
			}
		}
	}

	private static bool GetBoolProperty(PropertyInfo property, object instance)
	{
		if (property == null || instance == null)
		{
			return false;
		}
		object value = property.GetValue(instance, null);
		if (value is bool)
		{
			return (bool)value;
		}
		return false;
	}

	private static void CanInteractPostfix(ref bool __result)
	{
		if (__result || !IsModActive())
		{
			return;
		}
		object localEquipmentManager = GetLocalEquipmentManager();
		if (localEquipmentManager != null)
		{
			ToggleState state = GetState(localEquipmentManager);
			if (state != null && state.IsToggled && !(Time.time - state.LastMaintainTime > 0.5f))
			{
				__result = true;
			}
		}
	}

	private static object GetLocalEquipmentManager()
	{
		if (pGameManagerInstance == null || pGameManagerEquipmentManager == null)
		{
			return null;
		}
		object value = pGameManagerInstance.GetValue(null, null);
		if (value == null)
		{
			return null;
		}
		return pGameManagerEquipmentManager.GetValue(value, null);
	}

	private static void ToggleOn(object equipmentManager, ToggleState state)
	{
		state.IsToggled = true;
		state.AttackInProgress = false;
		state.SheatheAfterAttack = false;
		state.SuppressMeleeUntilReleased = false;
		state.NextChargeAttemptTime = Time.time + ClampRetryInterval();
		state.LastMaintainTime = Time.time;
		state.CompletingMeleeAttack = false;
		state.PendingTapHold = false;
		state.LongPressPassThrough = false;
		state.WasMeleeHeldLastFrame = false;
		state.MeleePressStartTime = 0f;
		ClearPendingWeaponSelection(state);
		ClearStanceAsLastUsed(state);
		if (LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)"Toggle melee ON.");
			}
		}
		InvokeChargeBasicMelee(equipmentManager);
		SetMeleePressed(equipmentManager, value: true);
	}

	private static void ToggleOff(object equipmentManager, ToggleState state)
	{
		if (LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)"Toggle melee OFF.");
			}
		}
		state.IsToggled = false;
		state.NextChargeAttemptTime = 0f;
		state.SuppressMeleeUntilReleased = true;
		state.PendingTapHold = false;
		state.LongPressPassThrough = false;
		state.WasMeleeHeldLastFrame = false;
		state.MeleePressStartTime = 0f;
		SetAlternativeMeleePressed(equipmentManager, value: false);
		SetMeleePressed(equipmentManager, value: false);
		object currentHoldable = GetCurrentHoldable(equipmentManager);
		if (state.AttackInProgress)
		{
			state.SheatheAfterAttack = true;
			if (LogStateChanges.Value)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"Melee attack is in progress. Will sheathe after current attack finishes.");
				}
			}
		}
		else
		{
			state.AttackInProgress = false;
			state.SheatheAfterAttack = false;
			CleanCurrentMeleeWeaponState(currentHoldable);
			InvokeOnMeleeDone(equipmentManager);
			RememberStanceAsLastUsed(equipmentManager, state);
		}
	}

	private static void MaintainToggledMelee(object equipmentManager, ToggleState state)
	{
		if (!state.AttackInProgress && !state.SheatheAfterAttack)
		{
			bool flag = IsAltFirePressed(equipmentManager);
			SetAlternativeMeleePressed(equipmentManager, flag);
			UpdateCurrentMeleeAlternativeAnimator(equipmentManager, flag);
			if (!IsInMeleeCharge(equipmentManager) && !(Time.time < state.NextChargeAttemptTime))
			{
				state.NextChargeAttemptTime = Time.time + ClampRetryInterval();
				InvokeChargeBasicMelee(equipmentManager);
				SetMeleePressed(equipmentManager, value: true);
			}
		}
	}

	private static void CacheSafeMeleeAnimatorStateIfUseful(object weapon, string source)
	{
		//IL_001c: 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)
		if (!IsMeleeWeapon(weapon))
		{
			return;
		}
		Animator animator = GetAnimator(weapon);
		if ((Object)(object)animator == (Object)null)
		{
			return;
		}
		AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
		string currentClipName = GetCurrentClipName(animator);
		if (!IsSafeMeleeDrawClip(currentClipName))
		{
			return;
		}
		SafeAnimatorState value = SafeAnimatorStates.GetValue(weapon, (object _) => new SafeAnimatorState());
		value.FullPathHash = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash;
		value.ShortNameHash = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).shortNameHash;
		value.ClipName = currentClipName;
		value.Valid = true;
		if (LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Cached safe melee animator state from " + source + ": clip=" + currentClipName + " fullPathHash=" + ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash));
			}
		}
	}

	private static bool IsSafeMeleeDrawClip(string clipName)
	{
		if (string.IsNullOrEmpty(clipName))
		{
			return false;
		}
		if (ContainsIgnoreCase(clipName, "Slash"))
		{
			return false;
		}
		if (ContainsIgnoreCase(clipName, "Attack"))
		{
			return false;
		}
		if (ContainsIgnoreCase(clipName, "Fire"))
		{
			return false;
		}
		if (ContainsIgnoreCase(clipName, "ADS"))
		{
			return false;
		}
		if (ContainsIgnoreCase(clipName, "ToADS"))
		{
			return false;
		}
		if (ContainsIgnoreCase(clipName, "Charge") || ContainsIgnoreCase(clipName, "Charged"))
		{
			return false;
		}
		return ContainsIgnoreCase(clipName, "Equip");
	}

	private static bool ContainsIgnoreCase(string value, string part)
	{
		if (value != null && part != null)
		{
			return value.IndexOf(part, StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return false;
	}

	private static void PrepareMeleeAnimatorForFutureDraw(object weapon)
	{
		if (!ResetMeleeAnimatorBeforeSheathe.Value || !IsMeleeWeapon(weapon))
		{
			return;
		}
		try
		{
			InvokeSetAlternativeState(weapon, 0);
			if (fCurrentParries != null)
			{
				fCurrentParries.SetValue(weapon, 0);
			}
			Animator animator = GetAnimator(weapon);
			if ((Object)(object)animator == (Object)null)
			{
				return;
			}
			animator.SetBool("Charge", false);
			animator.SetBool("Sprinting", false);
			animator.SetBool("AlternativePressed", false);
			animator.ResetTrigger("Parry");
			if (!SafeAnimatorStates.TryGetValue(weapon, out var value) || value == null || !value.Valid)
			{
				CacheSafeMeleeAnimatorStateIfUseful(weapon, "PrepareMeleeAnimatorForFutureDraw fallback");
				if (!SafeAnimatorStates.TryGetValue(weapon, out value) || value == null || !value.Valid)
				{
					if (LogStateChanges.Value)
					{
						ManualLogSource log = Log;
						if (log != null)
						{
							log.LogInfo((object)("No cached safe melee animator state available for " + weapon));
						}
					}
					return;
				}
			}
			animator.Play(value.FullPathHash, 0, 0f);
			animator.Update(0f);
			if (LogStateChanges.Value)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogInfo((object)("Reset melee animator to safe draw state before sheathe: " + value.ClipName + " hash=" + value.FullPathHash));
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource log3 = Log;
			if (log3 != null)
			{
				log3.LogError((object)("Failed to prepare melee animator for future draw: " + ex));
			}
		}
	}

	private static void CleanCurrentMeleeWeaponState(object currentHoldable)
	{
		if (!IsMeleeWeapon(currentHoldable))
		{
			return;
		}
		try
		{
			PrepareMeleeAnimatorForFutureDraw(currentHoldable);
		}
		catch (Exception ex)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogError((object)("Failed to clean melee weapon state: " + ex));
			}
		}
	}

	private static string GetCurrentClipName(Animator animator)
	{
		if ((Object)(object)animator == (Object)null)
		{
			return string.Empty;
		}
		try
		{
			AnimatorClipInfo[] currentAnimatorClipInfo = animator.GetCurrentAnimatorClipInfo(0);
			if (currentAnimatorClipInfo != null && currentAnimatorClipInfo.Length != 0 && (Object)(object)((AnimatorClipInfo)(ref currentAnimatorClipInfo[0])).clip != (Object)null)
			{
				return ((Object)((AnimatorClipInfo)(ref currentAnimatorClipInfo[0])).clip).name;
			}
		}
		catch
		{
			return string.Empty;
		}
		return string.Empty;
	}

	private static float ClampRetryInterval()
	{
		if (ReChargeRetryInterval == null)
		{
			return 0.08f;
		}
		float value = ReChargeRetryInterval.Value;
		if (float.IsNaN(value) || float.IsInfinity(value))
		{
			return 0.08f;
		}
		return Mathf.Clamp(value, 0.01f, 0.5f);
	}

	private static bool WasMeleePressedThisFrame(object equipmentManager)
	{
		InputAction inputAction = GetInputAction(fMeleeFireAction, equipmentManager);
		InputAction inputAction2 = GetInputAction(fMeleeFireActionAlternative, equipmentManager);
		if (!WasPerformedThisFrame(inputAction))
		{
			return WasPerformedThisFrame(inputAction2);
		}
		return true;
	}

	private static bool IsMeleeHeld(object equipmentManager)
	{
		InputAction inputAction = GetInputAction(fMeleeFireAction, equipmentManager);
		InputAction inputAction2 = GetInputAction(fMeleeFireActionAlternative, equipmentManager);
		bool num = inputAction != null && inputAction.IsPressed();
		bool flag = inputAction2 != null && inputAction2.IsPressed();
		return num || flag;
	}

	private static bool HandleTapHoldMeleeInput(object equipmentManager, ToggleState state, bool holdingMeleeAction, out bool prefixResult)
	{
		prefixResult = true;
		bool flag = holdingMeleeAction || IsMeleeHeld(equipmentManager);
		bool flag2 = flag && !state.WasMeleeHeldLastFrame;
		bool flag3 = !flag && state.WasMeleeHeldLastFrame;
		state.WasMeleeHeldLastFrame = flag;
		if (state.LongPressPassThrough)
		{
			if (flag3 || !flag)
			{
				state.LongPressPassThrough = false;
				state.PendingTapHold = false;
				state.MeleePressStartTime = 0f;
				if (LogStateChanges.Value)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogInfo((object)"Long melee input released. Original melee behavior finished.");
					}
				}
			}
			prefixResult = true;
			return true;
		}
		if (state.PendingTapHold)
		{
			float num = Time.time - state.MeleePressStartTime;
			if (flag3 || !flag)
			{
				state.PendingTapHold = false;
				if (num <= GetMeleeToggleTapThreshold())
				{
					ToggleOn(equipmentManager, state);
					if (LogStateChanges.Value)
					{
						ManualLogSource log2 = Log;
						if (log2 != null)
						{
							log2.LogInfo((object)"Melee key tap detected. Toggle melee ON.");
						}
					}
					prefixResult = false;
					return true;
				}
				prefixResult = true;
				return true;
			}
			if (num >= GetMeleeToggleTapThreshold())
			{
				state.PendingTapHold = false;
				state.LongPressPassThrough = true;
				if (LogStateChanges.Value)
				{
					ManualLogSource log3 = Log;
					if (log3 != null)
					{
						log3.LogInfo((object)"Melee key hold detected. Passing through to original melee behavior.");
					}
				}
				prefixResult = true;
				return true;
			}
			prefixResult = false;
			return true;
		}
		if (flag2)
		{
			state.PendingTapHold = true;
			state.MeleePressStartTime = Time.time;
			prefixResult = false;
			return true;
		}
		return false;
	}

	private static bool HandleTapHoldMeleeInputSwapped(object equipmentManager, ToggleState state, bool holdingMeleeAction, out bool prefixResult)
	{
		prefixResult = true;
		bool flag = holdingMeleeAction || IsMeleeHeld(equipmentManager);
		bool flag2 = flag && !state.WasMeleeHeldLastFrame;
		state.WasMeleeHeldLastFrame = flag;
		if (state.PendingTapHold)
		{
			float num = Time.time - state.MeleePressStartTime;
			if (!flag)
			{
				state.PendingTapHold = false;
				if (LogStateChanges.Value)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogInfo((object)"Melee key tap detected (swapped). Original quick melee attack.");
					}
				}
				prefixResult = true;
				return true;
			}
			if (num >= GetMeleeToggleTapThreshold())
			{
				state.PendingTapHold = false;
				ToggleOn(equipmentManager, state);
				if (LogStateChanges.Value)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"Melee key hold detected (swapped). Toggle melee ON.");
					}
				}
				prefixResult = false;
				return true;
			}
			prefixResult = true;
			return true;
		}
		if (flag2)
		{
			state.PendingTapHold = true;
			state.MeleePressStartTime = Time.time;
			prefixResult = true;
			return true;
		}
		return false;
	}

	private static float GetMeleeToggleTapThreshold()
	{
		if (MeleeToggleTapThreshold == null)
		{
			return 0.13f;
		}
		float value = MeleeToggleTapThreshold.Value;
		if (float.IsNaN(value) || float.IsInfinity(value))
		{
			return 0.13f;
		}
		return Mathf.Clamp(value, 0.05f, 0.6f);
	}

	private static bool ExitToggledStateIfExternalNonMeleeHoldable(object equipmentManager, ToggleState state, string source)
	{
		if (equipmentManager == null || state == null)
		{
			return false;
		}
		if (!state.IsToggled)
		{
			return false;
		}
		if (KeepMeleeStanceAfterExternalWeaponSwitch != null && KeepMeleeStanceAfterExternalWeaponSwitch.Value)
		{
			return false;
		}
		object currentHoldable = GetCurrentHoldable(equipmentManager);
		if (currentHoldable == null)
		{
			return false;
		}
		if (IsMeleeWeapon(currentHoldable))
		{
			return false;
		}
		ForceExitToggledStateAfterExternalWeaponSwitch(equipmentManager, state, currentHoldable, source);
		return true;
	}

	private static void ForceExitToggledStateAfterExternalWeaponSwitch(object equipmentManager, ToggleState state, object currentHoldable, string source)
	{
		state.IsToggled = false;
		state.AttackInProgress = false;
		state.SheatheAfterAttack = false;
		state.SuppressMeleeUntilReleased = false;
		state.NextChargeAttemptTime = 0f;
		state.PendingTapHold = false;
		state.LongPressPassThrough = false;
		state.WasMeleeHeldLastFrame = false;
		state.MeleePressStartTime = 0f;
		ClearPendingWeaponSelection(state);
		SetMeleePressed(equipmentManager, value: false);
		SetAlternativeMeleePressed(equipmentManager, value: false);
		RememberStanceAsLastUsed(equipmentManager, state);
		if (LogStateChanges != null && LogStateChanges.Value)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Exited toggle melee stance because current holdable is no longer melee. source=" + source + " holdable=" + currentHoldable));
			}
		}
	}

	private static bool IsAltFirePressed(object equipmentManager)
	{
		InputAction inputAction = GetInputAction(fAltFireAction, equipmentManager);
		if (inputAction != null)
		{
			return inputAction.IsPressed();
		}
		return false;
	}

	private static bool WasPerformedThisFrame(InputAction action)
	{
		if (action != null)
		{
			return action.WasPerformedThisFrame();
		}
		return false;
	}

	private static InputAction GetInputAction(FieldInfo field, object instance)
	{
		if (field == null || instance == null)
		{
			return null;
		}
		object? value = field.GetValue(instance);
		return (InputAction)((value is InputAction) ? value : null);
	}

	private static object GetCurrentHoldable(object equipmentManager)
	{
		if (fCurrentHoldable == null || equipmentManager == null)
		{
			return null;
		}
		return fCurrentHoldable.GetValue(equipmentManager);
	}

	private static object GetEquipmentManagerFromWeapon(object weapon)
	{
		if (fEquipmentManager == null || weapon == null)
		{
			return null;
		}
		return fEquipmentManager.GetValue(weapon);
	}

	private static bool IsMeleeWeapon(object holdable)
	{
		if (holdable == null)
		{
			return false;
		}
		if (!weaponType.IsInstanceOfType(holdable))
		{
			return false;
		}
		object value = pIsMelee.GetValue(holdable, null);
		if (value is bool)
		{
			return (bool)value;
		}
		return false;
	}

	private static bool IsMeleeCharging(object weapon)
	{
		if (weapon == null || mIsMeleeCharging == null)
		{
			return false;
		}
		object obj = mIsMeleeCharging.Invoke(weapon, null);
		if (obj is bool)
		{
			return (bool)obj;
		}
		return false;
	}

	private static bool IsInMeleeCharge(object equipmentManager)
	{
		return GetBoolField(fIsInMeleeCharge, equipmentManager);
	}

	private static bool IsAimingInputHeld(object equipmentManager)
	{
		return GetBoolField(fAimingInputHeld, equipmentManager);
	}

	private static bool IsMeleeInputCoolingDown(object equipmentManager)
	{
		if (fMeleeInputCooldown == null || equipmentManager == null)
		{
			return false;
		}
		object value = fMeleeInputCooldown.GetValue(equipmentManager);
		if (!(value is float))
		{
			return false;
		}
		return Time.time < (float)value;
	}

	private static bool GetBoolField(FieldInfo field, object instance)
	{
		if (field == null || instance == null)
		{
			return false;
		}
		object value = field.GetValue(instance);
		if (value is bool)
		{
			return (bool)value;
		}
		return false;
	}

	private static void SetMeleePressed(object equipmentManager, bool value)
	{
		SetBoolField(fMeleePressed, equipmentManager, value);
	}

	private static void SetAlternativeMeleePressed(object equipmentManager, bool value)
	{
		SetBoolField(fAlternativeMeleePressed, equipmentManager, value);
	}

	private static void SetBoolField(FieldInfo field, object instance, bool value)
	{
		if (!(field == null) && instance != null)
		{
			field.SetValue(instance, value);
		}
	}

	private static void UpdateCurrentMeleeAlternativeAnimator(object equipmentManager, bool altHeld)
	{
		object currentHoldable = GetCurrentHoldable(equipmentManager);
		if (IsMeleeWeapon(currentHoldable))
		{
			Animator animator = GetAnimator(currentHoldable);
			if (!((Object)(object)animator == (Object)null))
			{
				animator.SetBool("AlternativePressed", altHeld);
			}
		}
	}

	private static Animator GetAnimator(object holdable)
	{
		if (holdable == null || pAnimator == null)
		{
			return null;
		}
		object? value = pAnimator.GetValue(holdable, null);
		return (Animator)((value is Animator) ? value : null);
	}

	private static void InvokeChargeBasicMelee(object equipmentManager)
	{
		try
		{
			mChargeBasicMelee.Invoke(equipmentManager, null);
		}
		catch (Exception ex)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogError((object)("Failed to invoke ChargeBasicMelee: " + ex));
			}
		}
	}

	private static void InvokeUseBasicMelee(object equipmentManager)
	{
		try
		{
			mUseBasicMelee.Invoke(equipmentManager, null);
		}
		catch (Exception ex)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogError((object)("Failed to invoke UseBasicMelee: " + ex));
			}
		}
	}

	private static void InvokeOnMeleeDone(object equipmentManager)
	{
		try
		{
			mOnMeleeDone.Invoke(equipmentManager, null);
		}
		catch (Exception ex)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogError((object)("Failed to invoke OnMeleeDone: " + ex));
			}
		}
	}

	private static void InvokeSetAlternativeState(object weapon, int value)
	{
		if (weapon == null || mSetAlternativeState == null)
		{
			return;
		}
		try
		{
			mSetAlternativeState.Invoke(weapon, new object[1] { value });
		}
		catch (Exception ex)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogError((object)("Failed to invoke SetAlternativeState: " + ex));
			}
		}
	}
}