Decompiled source of AskaFirstPerson v1.0.2

BepInEx\plugins\AskaFirstPerson\AskaFirstPerson.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Fusion;
using HarmonyLib;
using HarmonyLib.Tools;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AskaFirstPerson
{
	[HarmonyPatch("Cinemachine.CinemachineBrain", "LateUpdate")]
	public static class CinemachineBrainPatch
	{
		[HarmonyPrefix]
		public static bool Prefix()
		{
			return !FirstPersonBehaviour.IsFirstPerson;
		}
	}
	public class FirstPersonBehaviour : MonoBehaviour
	{
		public static bool IsFirstPerson;

		internal static string SuppressedToggleButtonName;

		internal static bool ChordModifierIsHeld;

		internal static bool InSelfRead;

		private Camera _cam;

		private Transform _headBone;

		private Transform _playerRoot;

		private Transform _characterRoot;

		private Transform _skeletonRoot;

		private Transform _leftHand;

		private Transform _rightHand;

		private Transform _spine;

		private Transform _spine1;

		private Gamepad _gamepad;

		private float _pitch;

		private float _yaw;

		private float _savedFOV;

		private float _savedNearClip;

		private Vector3 _smoothVelocity;

		private Vector3 _stableBasePos;

		private readonly List<Renderer> _shadowOnlyRenderers = new List<Renderer>();

		private float _rendererScanTimer;

		private const float RendererScanInterval = 0.5f;

		private static readonly string[] LowerBodyPrefixes = new string[6] { "ragnar_base_forearm", "ragnar_base_hand", "ragnar_base_pants", "ragnar_base_boots", "ragnar_base_belt", "ragnar_base_glove" };

		private void Update()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			if (!IsInGameplay())
			{
				if (IsFirstPerson)
				{
					IsFirstPerson = false;
					DisableFirstPerson();
					ClearCachedReferences();
					FirstPersonPlugin.Log.LogInfo((object)"Left gameplay — first-person auto-disabled");
				}
				return;
			}
			try
			{
				_gamepad = Gamepad.current;
			}
			catch
			{
				_gamepad = null;
			}
			if (Input.GetKeyDown(FirstPersonPlugin.CfgToggleKey.Value) || TryReadGamepadToggle())
			{
				IsFirstPerson = !IsFirstPerson;
				if (IsFirstPerson)
				{
					EnableFirstPerson();
				}
				else
				{
					DisableFirstPerson();
				}
				ManualLogSource log = FirstPersonPlugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(19, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("First-person mode: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(IsFirstPerson ? "ON" : "OFF");
				}
				log.LogInfo(val);
			}
			if (!IsFirstPerson || (Object)(object)_cam == (Object)null || IsGamePaused())
			{
				return;
			}
			float value = FirstPersonPlugin.CfgSensitivity.Value;
			_yaw += Input.GetAxis("Mouse X") * value;
			_pitch -= Input.GetAxis("Mouse Y") * value;
			if (_gamepad != null)
			{
				try
				{
					Vector2 val2 = ((InputControl<Vector2>)(object)_gamepad.rightStick).ReadValue();
					float num = value * 3f;
					_yaw += val2.x * num * Time.deltaTime * 60f;
					_pitch -= val2.y * num * Time.deltaTime * 60f;
				}
				catch
				{
				}
			}
			_pitch = Mathf.Clamp(_pitch, -85f, 85f);
		}

		private bool TryReadGamepadToggle()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			if (_gamepad == null)
			{
				ResetSuppressionState();
				return false;
			}
			try
			{
				InSelfRead = true;
				try
				{
					string value = FirstPersonPlugin.CfgGamepadToggleButton.Value;
					ButtonControl gamepadButton = GetGamepadButton(_gamepad, value);
					string value2 = FirstPersonPlugin.CfgGamepadModifierButton.Value;
					bool flag = string.Equals(value2, "None", StringComparison.OrdinalIgnoreCase);
					bool flag2 = false;
					if (!flag)
					{
						ButtonControl gamepadButton2 = GetGamepadButton(_gamepad, value2);
						flag2 = gamepadButton2 != null && gamepadButton2.isPressed;
					}
					bool chordModifierIsHeld = ChordModifierIsHeld;
					SuppressedToggleButtonName = ((flag || gamepadButton == null) ? null : ((InputControl)gamepadButton).name);
					ChordModifierIsHeld = flag2;
					if (chordModifierIsHeld != flag2)
					{
						InputSuppressionPatch.LoggedMagnitudeThisHold = false;
					}
					if (flag2 && gamepadButton != null)
					{
						try
						{
							InputState.Change<float>((InputControl)(object)gamepadButton, 0f, (InputUpdateType)0, default(InputEventPtr));
						}
						catch
						{
						}
					}
					return gamepadButton != null && gamepadButton.wasPressedThisFrame && (flag || flag2);
				}
				finally
				{
					InSelfRead = false;
				}
			}
			catch
			{
				return false;
			}
		}

		private static void ResetSuppressionState()
		{
			SuppressedToggleButtonName = null;
			ChordModifierIsHeld = false;
			InputSuppressionPatch.LoggedMagnitudeThisHold = false;
		}

		private void LateUpdate()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			if (!IsFirstPerson)
			{
				return;
			}
			if ((Object)(object)_cam == (Object)null || (Object)(object)_headBone == (Object)null)
			{
				TryFindReferences();
			}
			else
			{
				if (IsGamePaused())
				{
					return;
				}
				float value = FirstPersonPlugin.CfgMotionDampening.Value;
				float x = _headBone.position.x;
				float z = _headBone.position.z;
				float y = _headBone.position.y;
				float num = Mathf.Lerp(30f, 6f, value);
				_stableBasePos.y = Mathf.Lerp(_stableBasePos.y, y, Time.deltaTime * num);
				float num2 = Mathf.Lerp(y, _stableBasePos.y, value);
				Vector3 val = new Vector3(x, num2, z);
				Vector3 forward = ((Component)_cam).transform.forward;
				Vector3 val2 = val + Vector3.up * FirstPersonPlugin.CfgVerticalOffset.Value + forward * FirstPersonPlugin.CfgForwardOffset.Value;
				((Component)_cam).transform.position = Vector3.SmoothDamp(((Component)_cam).transform.position, val2, ref _smoothVelocity, 1f / FirstPersonPlugin.CfgSmoothSpeed.Value);
				((Component)_cam).transform.rotation = Quaternion.Euler(_pitch, _yaw, 0f);
				if ((Object)(object)_spine != (Object)null && (Object)(object)_playerRoot != (Object)null)
				{
					float num3 = Mathf.Clamp(Mathf.DeltaAngle(_playerRoot.eulerAngles.y, _yaw), -80f, 80f) * 0.5f;
					_spine.localRotation *= Quaternion.Euler(0f, num3, 0f);
					if ((Object)(object)_spine1 != (Object)null)
					{
						_spine1.localRotation *= Quaternion.Euler(0f, num3, 0f);
					}
				}
				_rendererScanTimer += Time.deltaTime;
				if (_rendererScanTimer >= 0.5f)
				{
					_rendererScanTimer = 0f;
					HidePlayerRenderers(rebuildCache: false);
				}
			}
		}

		private void EnableFirstPerson()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			TryFindReferences();
			if ((Object)(object)_cam == (Object)null)
			{
				FirstPersonPlugin.Log.LogWarning((object)"Cannot enable first-person — main camera not found. Ensure you are in-game (not a loading screen).");
				IsFirstPerson = false;
				return;
			}
			_savedFOV = _cam.fieldOfView;
			_savedNearClip = _cam.nearClipPlane;
			_cam.fieldOfView = FirstPersonPlugin.CfgFOV.Value;
			_cam.nearClipPlane = FirstPersonPlugin.CfgNearClip.Value;
			Vector3 eulerAngles = ((Component)_cam).transform.eulerAngles;
			_yaw = eulerAngles.y;
			_pitch = ((eulerAngles.x > 180f) ? (eulerAngles.x - 360f) : eulerAngles.x);
			_stableBasePos = (((Object)(object)_headBone != (Object)null) ? _headBone.position : ((Component)_cam).transform.position);
			if ((Object)(object)_headBone != (Object)null && (Object)(object)_playerRoot != (Object)null)
			{
				float y = _playerRoot.position.y;
				float y2 = _headBone.position.y;
				ManualLogSource log = FirstPersonPlugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(73, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Diagnostics] PlayerRoot Y=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(y, "F2");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", HeadBone Y=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(y2, "F2");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("HeadHeight=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(y2 - y, "F2");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", Camera Y=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(((Component)_cam).transform.position.y, "F2");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Player=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)_playerRoot).name);
				}
				log.LogInfo(val);
			}
			HidePlayerRenderers(rebuildCache: true);
		}

		private void DisableFirstPerson()
		{
			if ((Object)(object)_cam != (Object)null)
			{
				_cam.fieldOfView = _savedFOV;
				_cam.nearClipPlane = _savedNearClip;
			}
			ShowPlayerModel();
		}

		private void TryFindReferences()
		{
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			if ((Object)(object)_cam == (Object)null)
			{
				_cam = Camera.main;
			}
			bool flag = default(bool);
			if ((Object)(object)_playerRoot == (Object)null)
			{
				GameObject val = FindLocalPlayer();
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				_playerRoot = val.transform;
				Transform val2 = _playerRoot.Find("GeometryParent");
				BepInExInfoLogInterpolatedStringHandler val4;
				if ((Object)(object)val2 != (Object)null)
				{
					for (int i = 0; i < val2.childCount; i++)
					{
						Transform child = val2.GetChild(i);
						Transform val3 = child.Find("master");
						if ((Object)(object)val3 != (Object)null)
						{
							_characterRoot = child;
							_skeletonRoot = val3;
							ManualLogSource log = FirstPersonPlugin.Log;
							val4 = new BepInExInfoLogInterpolatedStringHandler(37, 2, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Character geometry root: ");
								((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(((Object)child).name);
								((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", skeleton: ");
								((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(((Object)val3).name);
							}
							log.LogInfo(val4);
							break;
						}
					}
				}
				ManualLogSource log2 = FirstPersonPlugin.Log;
				val4 = new BepInExInfoLogInterpolatedStringHandler(14, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Local player: ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(((Object)val).name);
				}
				log2.LogInfo(val4);
			}
			if (!((Object)(object)_skeletonRoot != (Object)null))
			{
				return;
			}
			if ((Object)(object)_headBone == (Object)null)
			{
				_headBone = _skeletonRoot.Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 Spine1/Bip001 Neck/Bip001 Head");
				if ((Object)(object)_headBone != (Object)null)
				{
					ManualLogSource log3 = FirstPersonPlugin.Log;
					BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(20, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Head bone resolved: ");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(((Object)_headBone).name);
					}
					log3.LogInfo(val4);
				}
				else
				{
					FirstPersonPlugin.Log.LogWarning((object)"Could not find head bone via explicit path. The skeleton hierarchy may have changed.");
				}
			}
			if ((Object)(object)_leftHand == (Object)null)
			{
				_leftHand = _skeletonRoot.Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 Spine1/Bip001 L Clavicle/Bip001 L UpperArm/Bip001 L Forearm/Bip001 L Hand");
			}
			if ((Object)(object)_rightHand == (Object)null)
			{
				_rightHand = _skeletonRoot.Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 Spine1/Bip001 R Clavicle/Bip001 R UpperArm/Bip001 R Forearm/Bip001 R Hand");
			}
			if ((Object)(object)_spine == (Object)null)
			{
				_spine = _skeletonRoot.Find("Bip001/Bip001 Pelvis/Bip001 Spine");
			}
			if ((Object)(object)_spine1 == (Object)null)
			{
				_spine1 = _skeletonRoot.Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 Spine1");
			}
		}

		private static bool IsLowerBody(string name)
		{
			string[] lowerBodyPrefixes = LowerBodyPrefixes;
			foreach (string value in lowerBodyPrefixes)
			{
				if (name.StartsWith(value, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsChildOf(Transform t, Transform ancestor)
		{
			if ((Object)(object)ancestor == (Object)null)
			{
				return false;
			}
			Transform parent = t.parent;
			while ((Object)(object)parent != (Object)null)
			{
				if ((Object)(object)parent == (Object)(object)ancestor)
				{
					return true;
				}
				parent = parent.parent;
			}
			return false;
		}

		private void HidePlayerRenderers(bool rebuildCache)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			if ((Object)(object)_playerRoot == (Object)null)
			{
				return;
			}
			if (rebuildCache)
			{
				_shadowOnlyRenderers.Clear();
			}
			bool value = FirstPersonPlugin.CfgShowBody.Value;
			foreach (Renderer componentsInChild in ((Component)_playerRoot).GetComponentsInChildren<Renderer>())
			{
				if (!((Object)(object)componentsInChild == (Object)null) && componentsInChild.enabled && (int)componentsInChild.shadowCastingMode != 3 && !IsChildOf(((Component)componentsInChild).transform, _leftHand) && !IsChildOf(((Component)componentsInChild).transform, _rightHand) && (!value || !((Object)(object)_characterRoot != (Object)null) || !((Object)(object)((Component)componentsInChild).transform.parent == (Object)(object)_characterRoot) || !IsLowerBody(((Object)((Component)componentsInChild).gameObject).name)))
				{
					componentsInChild.shadowCastingMode = (ShadowCastingMode)3;
					_shadowOnlyRenderers.Add(componentsInChild);
				}
			}
			if (rebuildCache)
			{
				FirstPersonPlugin.Log.LogInfo((object)($"Set {_shadowOnlyRenderers.Count} renderers to shadow-only " + "(body + equipment + accessories; hands kept visible)"));
			}
		}

		private void ShowPlayerModel()
		{
			foreach (Renderer shadowOnlyRenderer in _shadowOnlyRenderers)
			{
				if ((Object)(object)shadowOnlyRenderer != (Object)null)
				{
					shadowOnlyRenderer.shadowCastingMode = (ShadowCastingMode)1;
				}
			}
			_shadowOnlyRenderers.Clear();
		}

		private GameObject FindLocalPlayer()
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			Il2CppReferenceArray<GameObject> val = GameObject.FindGameObjectsWithTag("Player");
			if (val == null || ((Il2CppArrayBase<GameObject>)(object)val).Length == 0)
			{
				return null;
			}
			if (((Il2CppArrayBase<GameObject>)(object)val).Length == 1)
			{
				return ((Il2CppArrayBase<GameObject>)(object)val)[0];
			}
			try
			{
				foreach (GameObject item in (Il2CppArrayBase<GameObject>)(object)val)
				{
					NetworkObject component = item.GetComponent<NetworkObject>();
					if ((Object)(object)component != (Object)null && component.HasInputAuthority)
					{
						return item;
					}
				}
			}
			catch
			{
			}
			if ((Object)(object)_cam == (Object)null)
			{
				_cam = Camera.main;
			}
			if ((Object)(object)_cam == (Object)null)
			{
				return ((Il2CppArrayBase<GameObject>)(object)val)[0];
			}
			GameObject result = null;
			float num = float.MaxValue;
			foreach (GameObject item2 in (Il2CppArrayBase<GameObject>)(object)val)
			{
				float num2 = Vector3.Distance(item2.transform.position, ((Component)_cam).transform.position);
				if (num2 < num)
				{
					num = num2;
					result = item2;
				}
			}
			return result;
		}

		private static bool IsInGameplay()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).name == "StreamingWorld";
		}

		private void ClearCachedReferences()
		{
			_cam = null;
			_headBone = null;
			_playerRoot = null;
			_characterRoot = null;
			_skeletonRoot = null;
			_leftHand = null;
			_rightHand = null;
			_spine = null;
			_spine1 = null;
			ResetSuppressionState();
		}

		private static bool IsGamePaused()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			if (Time.timeScale == 0f)
			{
				return true;
			}
			if (Cursor.visible || (int)Cursor.lockState != 1)
			{
				return true;
			}
			return false;
		}

		private static ButtonControl GetGamepadButton(Gamepad pad, string name)
		{
			switch (name)
			{
			case "North":
			case "ButtonNorth":
				return pad.buttonNorth;
			case "South":
			case "ButtonSouth":
				return pad.buttonSouth;
			case "East":
			case "ButtonEast":
				return pad.buttonEast;
			case "West":
			case "ButtonWest":
				return pad.buttonWest;
			case "LeftBumper":
			case "LeftShoulder":
				return pad.leftShoulder;
			case "RightBumper":
			case "RightShoulder":
				return pad.rightShoulder;
			case "LeftTrigger":
				return pad.leftTrigger;
			case "RightTrigger":
				return pad.rightTrigger;
			case "LeftStickButton":
				return pad.leftStickButton;
			case "RightStickButton":
				return pad.rightStickButton;
			case "Start":
			case "StartButton":
				return pad.startButton;
			case "SelectButton":
			case "Select":
				return pad.selectButton;
			case "DpadUp":
				return pad.dpad.up;
			case "DpadDown":
				return pad.dpad.down;
			case "DpadLeft":
				return pad.dpad.left;
			case "DpadRight":
				return pad.dpad.right;
			default:
				return null;
			}
		}
	}
	[BepInPlugin("com.community.askafirstperson", "Aska First Person Camera", "1.0.2")]
	public class FirstPersonPlugin : BasePlugin
	{
		public const string PluginGuid = "com.community.askafirstperson";

		public const string PluginName = "Aska First Person Camera";

		public const string PluginVersion = "1.0.2";

		internal static ManualLogSource Log;

		public static ConfigEntry<float> CfgFOV;

		public static ConfigEntry<float> CfgSensitivity;

		public static ConfigEntry<float> CfgNearClip;

		public static ConfigEntry<float> CfgVerticalOffset;

		public static ConfigEntry<float> CfgForwardOffset;

		public static ConfigEntry<float> CfgSmoothSpeed;

		public static ConfigEntry<float> CfgMotionDampening;

		public static ConfigEntry<bool> CfgShowBody;

		public static ConfigEntry<KeyCode> CfgToggleKey;

		public static ConfigEntry<string> CfgGamepadToggleButton;

		public static ConfigEntry<string> CfgGamepadModifierButton;

		public override void Load()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Expected O, but got Unknown
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Expected O, but got Unknown
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Expected O, but got Unknown
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Expected O, but got Unknown
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BasePlugin)this).Log;
			CfgFOV = ((BasePlugin)this).Config.Bind<float>("Camera", "FOV", 80f, new ConfigDescription("First-person field of view", (AcceptableValueBase)(object)new AcceptableValueRange<float>(60f, 120f), Array.Empty<object>()));
			CfgSensitivity = ((BasePlugin)this).Config.Bind<float>("Camera", "MouseSensitivity", 2f, new ConfigDescription("Mouse look sensitivity", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			CfgNearClip = ((BasePlugin)this).Config.Bind<float>("Camera", "NearClipPlane", 0.05f, "Near clip plane distance — lower values prevent seeing inside geometry");
			CfgVerticalOffset = ((BasePlugin)this).Config.Bind<float>("Camera", "VerticalOffset", 0.1f, "Vertical offset above the head bone (metres)");
			CfgForwardOffset = ((BasePlugin)this).Config.Bind<float>("Camera", "ForwardOffset", 0.12f, "Forward offset from the head bone (metres)");
			CfgSmoothSpeed = ((BasePlugin)this).Config.Bind<float>("Camera", "SmoothSpeed", 15f, new ConfigDescription("Position smoothing factor — higher = less smoothing", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			CfgMotionDampening = ((BasePlugin)this).Config.Bind<float>("Camera", "MotionDampening", 0.4f, new ConfigDescription("Reduces vertical camera shake from combat, rolls, and head bob. Only affects up/down movement — lateral tracking stays responsive. 0 = no dampening (raw head tracking), 1 = maximum dampening. Recommended 0.3-0.5.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			CfgShowBody = ((BasePlugin)this).Config.Bind<bool>("Visibility", "ShowLowerBody", false, "Show lower body (forearms, hands, legs) in first-person. Off = cleaner look (shadow-only body, weapons visible). On = see arms/legs but may have visual artifacts (mesh seams, backface culling).");
			CfgToggleKey = ((BasePlugin)this).Config.Bind<KeyCode>("Controls", "ToggleKey", (KeyCode)286, "Key to toggle between first-person and third-person camera");
			CfgGamepadToggleButton = ((BasePlugin)this).Config.Bind<string>("Controls", "GamepadToggleButton", "RightStickButton", "Gamepad button to toggle first-person mode. Valid: North, South, East, West, LeftShoulder, RightShoulder, LeftTrigger, RightTrigger, LeftStickButton, RightStickButton, Start, Select, DpadUp, DpadDown, DpadLeft, DpadRight");
			CfgGamepadModifierButton = ((BasePlugin)this).Config.Bind<string>("Controls", "GamepadModifierButton", "LeftShoulder", "Modifier button that must be held while pressing the toggle button. Set to \"None\" to disable the modifier (bare button press). Default: LeftShoulder (LB + R3 chord avoids conflicting with game actions). Valid: None, North, South, East, West, LeftShoulder, RightShoulder, LeftTrigger, RightTrigger, LeftStickButton, RightStickButton, Start, Select, DpadUp, DpadDown, DpadLeft, DpadRight");
			Harmony harmony = new Harmony("com.community.askafirstperson");
			List<string> list = new List<string>();
			LogChannel channelFilter = Logger.ChannelFilter;
			Logger.ChannelFilter = (LogChannel)(channelFilter & -9);
			try
			{
				if (TryPatchClass(harmony, typeof(CinemachineBrainPatch)))
				{
					list.Add("Cinemachine");
				}
				(string, Type)[] patchClasses = InputSuppressionPatch.PatchClasses;
				for (int i = 0; i < patchClasses.Length; i++)
				{
					var (item, type) = patchClasses[i];
					if (TryPatchClass(harmony, type))
					{
						list.Add(item);
					}
				}
			}
			finally
			{
				Logger.ChannelFilter = channelFilter;
			}
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(26, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Harmony patches active: [");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(", ", list));
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]");
			}
			log.LogInfo(val);
			((BasePlugin)this).AddComponent<FirstPersonBehaviour>();
			string value = CfgGamepadModifierButton.Value;
			string value2 = CfgGamepadToggleButton.Value;
			string text = (string.Equals(value, "None", StringComparison.OrdinalIgnoreCase) ? value2 : (value + "+" + value2));
			ManualLogSource log2 = Log;
			val = new BepInExInfoLogInterpolatedStringHandler(44, 4, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Aska First Person Camera");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.2");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded — press [");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<KeyCode>(CfgToggleKey.Value);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] or gamepad [");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] to toggle");
			}
			log2.LogInfo(val);
		}

		private static bool TryPatchClass(Harmony harmony, Type type)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			try
			{
				harmony.CreateClassProcessor(type).Patch();
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(25, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Skipping Harmony patch ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(type.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
				return false;
			}
		}
	}
	internal static class InputSuppressionPatch
	{
		[HarmonyPatch("UnityEngine.InputSystem.InputControl", "EvaluateMagnitude")]
		[HarmonyPatch(new Type[] { })]
		public static class EvaluateMagnitudePatch
		{
			[HarmonyPostfix]
			public static void Postfix(InputControl __instance, ref float __result)
			{
				if (!(__result <= 0f) && ShouldSuppressControl(__instance))
				{
					__result = 0f;
					LogOnce(ref LoggedMagnitudeThisHold, "Magnitude", "InputControl.EvaluateMagnitude(" + __instance.name + ") -> 0");
				}
			}
		}

		internal static bool LoggedMagnitudeThisHold;

		internal static readonly (string Layer, Type PatchClass)[] PatchClasses = new(string, Type)[1] { ("Magnitude", typeof(EvaluateMagnitudePatch)) };

		private static bool ShouldSuppressControl(InputControl instance)
		{
			if (instance == null)
			{
				return false;
			}
			if (FirstPersonBehaviour.InSelfRead)
			{
				return false;
			}
			if (!FirstPersonBehaviour.ChordModifierIsHeld)
			{
				return false;
			}
			string suppressedToggleButtonName = FirstPersonBehaviour.SuppressedToggleButtonName;
			if (string.IsNullOrEmpty(suppressedToggleButtonName))
			{
				return false;
			}
			try
			{
				return string.Equals(instance.name, suppressedToggleButtonName, StringComparison.Ordinal);
			}
			catch
			{
				return false;
			}
		}

		private static void LogOnce(ref bool latch, string layerTag, string detail)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			if (latch)
			{
				return;
			}
			latch = true;
			try
			{
				ManualLogSource log = FirstPersonPlugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(12, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Suppress.");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(layerTag);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(detail);
				}
				log.LogInfo(val);
			}
			catch
			{
			}
		}
	}
}