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 _shadowOnlyRenderers = new List(); 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(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)(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, -89f, 89f); } 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((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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_015b: 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_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: 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 deltaTime = Time.deltaTime; if (deltaTime <= 0f) { return; } Vector3 position = _headBone.position; if (!IsFinite(position)) { return; } float value = FirstPersonPlugin.CfgMotionDampening.Value; float x = position.x; float z = position.z; float y = position.y; float num = Mathf.Lerp(30f, 6f, value); _stableBasePos.y = Mathf.Lerp(_stableBasePos.y, y, 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; Vector3 val3 = Vector3.SmoothDamp(((Component)_cam).transform.position, val2, ref _smoothVelocity, 1f / FirstPersonPlugin.CfgSmoothSpeed.Value); if (IsFinite(val3)) { ((Component)_cam).transform.position = val3; } else { _smoothVelocity = Vector3.zero; } ((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(y, "F2"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", HeadBone Y="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(y2, "F2"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("HeadHeight="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(y2 - y, "F2"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", Camera Y="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((Component)_cam).transform.position.y, "F2"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Player="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(((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(((Object)child).name); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", skeleton: "); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted(((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(((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(((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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Invalid comparison between Unknown and I4 if ((Object)(object)_playerRoot == (Object)null) { return; } if (rebuildCache) { _shadowOnlyRenderers.Clear(); } bool value = FirstPersonPlugin.CfgShowBody.Value; Renderer[] array; try { array = Il2CppArrayBase.op_Implicit(((Component)_playerRoot).GetComponentsInChildren()); } catch { return; } if (array == null) { return; } Renderer[] array2 = array; foreach (Renderer val in array2) { try { if (!((Object)(object)val == (Object)null) && val.enabled && (int)val.shadowCastingMode != 3 && !IsChildOf(((Component)val).transform, _leftHand) && !IsChildOf(((Component)val).transform, _rightHand) && (!value || !((Object)(object)_characterRoot != (Object)null) || !((Object)(object)((Component)val).transform.parent == (Object)(object)_characterRoot) || !IsLowerBody(((Object)((Component)val).gameObject).name))) { val.shadowCastingMode = (ShadowCastingMode)3; _shadowOnlyRenderers.Add(val); } } catch { } } if (!rebuildCache && _shadowOnlyRenderers.Count > 0) { _shadowOnlyRenderers.RemoveAll((Renderer r) => (Object)(object)r == (Object)null); } 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) { try { if ((Object)(object)shadowOnlyRenderer != (Object)null) { shadowOnlyRenderer.shadowCastingMode = (ShadowCastingMode)1; } } catch { } } _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 val = GameObject.FindGameObjectsWithTag("Player"); if (val == null || ((Il2CppArrayBase)(object)val).Length == 0) { return null; } if (((Il2CppArrayBase)(object)val).Length == 1) { return ((Il2CppArrayBase)(object)val)[0]; } try { foreach (GameObject item in (Il2CppArrayBase)(object)val) { NetworkObject component = item.GetComponent(); 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)(object)val)[0]; } GameObject result = null; float num = float.MaxValue; foreach (GameObject item2 in (Il2CppArrayBase)(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 bool IsFinite(Vector3 v) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(v.x) && !float.IsNaN(v.y) && !float.IsNaN(v.z) && !float.IsInfinity(v.x) && !float.IsInfinity(v.y)) { return !float.IsInfinity(v.z); } 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.3")] 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.3"; internal static ManualLogSource Log; public static ConfigEntry CfgFOV; public static ConfigEntry CfgSensitivity; public static ConfigEntry CfgNearClip; public static ConfigEntry CfgVerticalOffset; public static ConfigEntry CfgForwardOffset; public static ConfigEntry CfgSmoothSpeed; public static ConfigEntry CfgMotionDampening; public static ConfigEntry CfgShowBody; public static ConfigEntry CfgToggleKey; public static ConfigEntry CfgGamepadToggleButton; public static ConfigEntry 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("Camera", "FOV", 80f, new ConfigDescription("First-person field of view", (AcceptableValueBase)(object)new AcceptableValueRange(60f, 120f), Array.Empty())); CfgSensitivity = ((BasePlugin)this).Config.Bind("Camera", "MouseSensitivity", 2f, new ConfigDescription("Mouse look sensitivity", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); CfgNearClip = ((BasePlugin)this).Config.Bind("Camera", "NearClipPlane", 0.05f, "Near clip plane distance — lower values prevent seeing inside geometry"); CfgVerticalOffset = ((BasePlugin)this).Config.Bind("Camera", "VerticalOffset", 0.1f, "Vertical offset above the head bone (metres)"); CfgForwardOffset = ((BasePlugin)this).Config.Bind("Camera", "ForwardOffset", 0.12f, "Forward offset from the head bone (metres)"); CfgSmoothSpeed = ((BasePlugin)this).Config.Bind("Camera", "SmoothSpeed", 15f, new ConfigDescription("Position smoothing factor — higher = less smoothing", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); CfgMotionDampening = ((BasePlugin)this).Config.Bind("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(0f, 1f), Array.Empty())); CfgShowBody = ((BasePlugin)this).Config.Bind("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("Controls", "ToggleKey", (KeyCode)286, "Key to toggle between first-person and third-person camera"); CfgGamepadToggleButton = ((BasePlugin)this).Config.Bind("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("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 list = new List(); 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.Join(", ", list)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]"); } log.LogInfo(val); ((BasePlugin)this).AddComponent(); 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("Aska First Person Camera"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("1.0.3"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded — press ["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(CfgToggleKey.Value); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] or gamepad ["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(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(type.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(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(layerTag); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(detail); } log.LogInfo(val); } catch { } } } }