Decompiled source of First Person View v1.0.1

BepInEx/plugins/FirstPersonView/FirstPersonView.dll

Decompiled 4 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FirstPersonView.Compat;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("FirstPersonView")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Lets players see their own body.")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+058a0c624f188a4e010b55984f0e2cc89f58d0f4")]
[assembly: AssemblyProduct("FirstPersonView")]
[assembly: AssemblyTitle("FirstPersonView")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FirstPersonView
{
	internal static class CameraRig
	{
		public static void ApplyOffset(LocalBodyState state, PlayerControllerB player)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			Camera gameplayCamera = state.GameplayCamera;
			if (!((Object)(object)gameplayCamera == (Object)null) && state.CameraBaseCaptured)
			{
				Transform transform = ((Component)gameplayCamera).transform;
				Transform parent = transform.parent;
				Vector3 val = (((Object)(object)parent != (Object)null) ? parent.up : Vector3.up);
				Vector3 val2 = Vector3.ProjectOnPlane(transform.forward, val);
				if (((Vector3)(ref val2)).sqrMagnitude < 1E-05f)
				{
					val2 = Vector3.ProjectOnPlane(((Component)player).transform.forward, val);
				}
				val2 = ((!(((Vector3)(ref val2)).sqrMagnitude < 1E-05f)) ? ((Vector3)(ref val2)).normalized : (((Object)(object)parent != (Object)null) ? parent.forward : Vector3.forward));
				Vector3 val3 = Vector3.Cross(val, val2);
				Quaternion yawRotation = Quaternion.LookRotation(val2, val);
				state.CrouchBlend = Mathf.MoveTowards(state.CrouchBlend, player.isCrouching ? 1f : 0f, Time.deltaTime / 0.15f);
				state.HoldBlend = Mathf.MoveTowards(state.HoldBlend, Players.IsHoldingTwoHanded(player) ? 1f : 0f, Time.deltaTime / 0.18f);
				state.RunBlend = Mathf.MoveTowards(state.RunBlend, player.isSprinting ? 1f : 0f, Time.deltaTime / 0.18f);
				state.JumpBlend = Mathf.MoveTowards(state.JumpBlend, (player.isJumping || player.isFallingFromJump) ? 1f : 0f, Time.deltaTime / 0.18f);
				float num = 0f + state.CrouchBlend * 0.12f + state.HoldBlend * 0.07f + state.RunBlend * 0.05f + state.JumpBlend * 0f;
				state.LadderBlend = Mathf.MoveTowards(state.LadderBlend, player.isClimbingLadder ? 1f : 0f, Time.deltaTime / 0.08f);
				float num2 = Mathf.Lerp(0.13f, 0f, state.LadderBlend) + state.HoldBlend * 0.15f + state.RunBlend * 0.1f + state.JumpBlend * 0.13f;
				Vector3 val4 = (((Object)(object)parent != (Object)null) ? parent.TransformPoint(state.CameraBaseLocalPosition) : state.CameraBaseLocalPosition);
				Vector3 val5 = FollowBodyAnchor(state, player, val4, yawRotation);
				Vector3 desired = val5 + val2 * num2 + val3 * 0f + val * num;
				desired = (transform.position = ResolveWallCollision(val4, desired));
				state.LastCameraTargetLocal = (((Object)(object)parent != (Object)null) ? parent.InverseTransformPoint(desired) : desired);
				state.HasCameraTarget = true;
				state.CameraOffsetApplied = true;
			}
		}

		public static void RelaxSeatedLookClamp(PlayerControllerB player)
		{
			if (player.inVehicleAnimation && player.clampLooking && player.minVerticalClamp < 75f)
			{
				player.minVerticalClamp = 75f;
			}
		}

		public static void AlignForInteractionRay(LocalBodyState state)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (state.HasCameraTarget && !((Object)(object)state.GameplayCamera == (Object)null))
			{
				Transform transform = ((Component)state.GameplayCamera).transform;
				Transform parent = transform.parent;
				transform.position = (((Object)(object)parent != (Object)null) ? parent.TransformPoint(state.LastCameraTargetLocal) : state.LastCameraTargetLocal);
			}
		}

		public static void ApplyArmAnchor(PlayerControllerB player, bool useVanillaArms)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if (!useVanillaArms || player.inSpecialInteractAnimation)
			{
				return;
			}
			Transform localArmsTransform = player.localArmsTransform;
			Camera gameplayCamera = player.gameplayCamera;
			Transform cameraContainerTransform = player.cameraContainerTransform;
			if (!((Object)(object)localArmsTransform == (Object)null) && !((Object)(object)gameplayCamera == (Object)null) && !((Object)(object)cameraContainerTransform == (Object)null))
			{
				Transform transform = ((Component)gameplayCamera).transform;
				localArmsTransform.position += transform.position - cameraContainerTransform.position;
				float value = ConfigManager.HandOffsetZ.Value;
				if (value != 0f)
				{
					localArmsTransform.position += transform.forward * value;
				}
			}
		}

		private static Vector3 FollowBodyAnchor(LocalBodyState state, PlayerControllerB player, Vector3 baseWorld, Quaternion yawRotation)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0101: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			Transform headBone = state.HeadBone;
			if ((Object)(object)headBone == (Object)null)
			{
				return baseWorld;
			}
			if (!state.EyeAnchorCaptured)
			{
				state.EyeAnchorLocal = Quaternion.Inverse(yawRotation) * (baseWorld - headBone.position);
				state.EyeAnchorBoneLocal = headBone.InverseTransformPoint(baseWorld);
				state.EyeAnchorCaptured = true;
			}
			if (TooManyEmotesCompat.IsFirstPersonEmoteActive())
			{
				return headBone.TransformPoint(state.EyeAnchorBoneLocal);
			}
			Vector3 val = headBone.position + yawRotation * state.EyeAnchorLocal;
			Vector3 val2 = Quaternion.Inverse(yawRotation) * (val - baseWorld);
			val2.x *= 1f;
			val2.z *= 1f;
			val2.y *= 1f;
			val2.y = DampHeadBob(state, player, val2.y);
			val2 = StabilizeSprintBob(state, player, val2);
			val2 = NeckGuardedFollow(state, player, val2);
			if (((Vector3)(ref val2)).sqrMagnitude > 0.25f)
			{
				val2 = ((Vector3)(ref val2)).normalized * 0.5f;
			}
			return baseWorld + yawRotation * val2;
		}

		private static float DampHeadBob(LocalBodyState state, PlayerControllerB player, float rawY)
		{
			if (!state.DisableBobSmoothInitialized)
			{
				state.DisableBobSmoothedY = rawY;
				state.DisableBobSmoothInitialized = true;
			}
			else
			{
				float num = 1f - Mathf.Exp((0f - Time.deltaTime) / 1f);
				state.DisableBobSmoothedY = Mathf.Lerp(state.DisableBobSmoothedY, rawY, num);
			}
			bool flag = ConfigManager.DisableHeadBob.Value && !player.isCrouching && state.CrouchBlend <= 0f && (player.isWalking || player.isSprinting || player.isJumping || player.isFallingFromJump);
			state.DisableBobBlend = Mathf.MoveTowards(state.DisableBobBlend, flag ? 1f : 0f, Time.deltaTime / 0.15f);
			return Mathf.Lerp(rawY, state.DisableBobSmoothedY, state.DisableBobBlend);
		}

		private static Vector3 StabilizeSprintBob(LocalBodyState state, PlayerControllerB player, Vector3 deviationLocal)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			bool flag = player.isSprinting || player.isJumping || player.isFallingFromJump;
			state.BobDampBlend = Mathf.MoveTowards(state.BobDampBlend, flag ? 1f : 0f, Time.deltaTime / 0.12f);
			if (!state.DeviationSmoothInitialized)
			{
				state.SmoothedDeviationLocal = deviationLocal;
				state.DeviationSmoothInitialized = true;
			}
			else
			{
				float num = 1f - Mathf.Exp((0f - Time.deltaTime) / 0.2f);
				state.SmoothedDeviationLocal = Vector3.Lerp(state.SmoothedDeviationLocal, deviationLocal, num);
			}
			float num2 = state.BobDampBlend * 0.6f;
			return Vector3.Lerp(deviationLocal, state.SmoothedDeviationLocal, num2);
		}

		private static Vector3 NeckGuardedFollow(LocalBodyState state, PlayerControllerB player, Vector3 live)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: 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_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: 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)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: 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_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
			if (!state.NeckGuardInitialized)
			{
				state.SwingRest = live;
				state.GuardedEyeDeviation = live;
				state.GuardedEyeVelocity = Vector3.zero;
				state.NeckGuardTail = 0f;
				state.NeckGuardRelease = 0f;
				state.NeckGuardLatched = false;
				state.NeckGuardWasSwinging = false;
				state.NeckGuardEngaged = false;
				state.NeckGuardFloorActive = false;
				state.NeckGuardCrouchRestZ = live.z;
				state.NeckGuardCrouchRestY = live.y;
				state.NeckGuardInitialized = true;
				return live;
			}
			bool flag = player.isCrouching && player.activatingItem;
			if (flag && !state.NeckGuardWasSwinging)
			{
				state.NeckGuardLatched = state.CrouchBlend >= 0.9f;
			}
			state.NeckGuardWasSwinging = flag;
			if (flag)
			{
				state.NeckGuardTail = 0.6f;
			}
			else if (state.NeckGuardTail > 0f)
			{
				state.NeckGuardTail -= Time.deltaTime;
			}
			bool flag2 = flag || state.NeckGuardTail > 0f;
			bool flag3 = state.NeckGuardLatched && player.isCrouching && flag2;
			if (player.isCrouching && !flag2)
			{
				state.NeckGuardCrouchRestZ = live.z;
				state.NeckGuardCrouchRestY = live.y;
			}
			bool flag4 = flag2 && player.isCrouching && !state.NeckGuardLatched;
			if (flag4 && !state.NeckGuardFloorActive)
			{
				state.NeckGuardFloorZ = Mathf.Max(state.NeckGuardCrouchRestZ, 0.35f);
				state.NeckGuardFloorActive = true;
			}
			else if (!flag4)
			{
				state.NeckGuardFloorActive = false;
			}
			if (state.NeckGuardEngaged && !flag3 && !flag4)
			{
				state.NeckGuardRelease = 0.8f;
			}
			else if (state.NeckGuardRelease > 0f)
			{
				state.NeckGuardRelease -= Time.deltaTime;
			}
			state.NeckGuardEngaged = flag3 || flag4;
			if (!flag3)
			{
				state.SwingRest = live;
			}
			Vector3 swingRest = state.SwingRest;
			Vector3 val = live;
			if (flag3)
			{
				val.z = Mathf.Max(live.z, swingRest.z);
				if (flag)
				{
					val.y = ((live.y >= swingRest.y) ? (swingRest.y + (live.y - swingRest.y) * 1f) : (swingRest.y + (live.y - swingRest.y) * 0f));
				}
				else
				{
					val.y = swingRest.y;
				}
			}
			else if (state.NeckGuardFloorActive)
			{
				val.z = Mathf.Max(live.z, state.NeckGuardFloorZ);
				float neckGuardCrouchRestY = state.NeckGuardCrouchRestY;
				val.y = ((!flag) ? neckGuardCrouchRestY : ((live.y >= neckGuardCrouchRestY) ? (neckGuardCrouchRestY + (live.y - neckGuardCrouchRestY) * 1f) : (neckGuardCrouchRestY + (live.y - neckGuardCrouchRestY) * 0f)));
			}
			bool flag5 = flag3 || (flag2 && player.isCrouching);
			float num = (flag5 ? 0.12f : ((!(state.NeckGuardRelease > 0f)) ? 0.015f : Mathf.Lerp(0.015f, 0.12f, state.NeckGuardRelease / 0.8f)));
			float num2 = (flag5 ? 0.12f : 0.015f);
			float x = state.GuardedEyeVelocity.x;
			float y = state.GuardedEyeVelocity.y;
			float z = state.GuardedEyeVelocity.z;
			state.GuardedEyeDeviation = new Vector3(Mathf.SmoothDamp(state.GuardedEyeDeviation.x, val.x, ref x, num), Mathf.SmoothDamp(state.GuardedEyeDeviation.y, val.y, ref y, num2), Mathf.SmoothDamp(state.GuardedEyeDeviation.z, val.z, ref z, num));
			state.GuardedEyeVelocity = new Vector3(x, y, z);
			return state.GuardedEyeDeviation;
		}

		private static Vector3 ResolveWallCollision(Vector3 origin, Vector3 desired)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return desired;
			}
			Vector3 val = desired - origin;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.0001f)
			{
				return desired;
			}
			Vector3 val2 = val / magnitude;
			float num = Mathf.Max(0.01f, 0.11f);
			RaycastHit val3 = default(RaycastHit);
			if (Physics.SphereCast(origin, num, val2, ref val3, magnitude, instance.collidersAndRoomMask, (QueryTriggerInteraction)1))
			{
				float num2 = Mathf.Clamp(((RaycastHit)(ref val3)).distance, 0f, magnitude);
				return origin + val2 * num2;
			}
			return desired;
		}

		public static void RestoreOffset(LocalBodyState state)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			state.CrouchBlend = 0f;
			state.LadderBlend = 0f;
			state.BobDampBlend = 0f;
			state.HoldBlend = 0f;
			state.RunBlend = 0f;
			state.JumpBlend = 0f;
			state.NeckGuardInitialized = false;
			state.NeckGuardTail = 0f;
			state.NeckGuardRelease = 0f;
			state.NeckGuardFloorActive = false;
			state.DeviationSmoothInitialized = false;
			state.DisableBobSmoothInitialized = false;
			state.DisableBobBlend = 0f;
			state.HasCameraTarget = false;
			if (state.CameraOffsetApplied)
			{
				Camera gameplayCamera = state.GameplayCamera;
				if ((Object)(object)gameplayCamera != (Object)null && state.CameraBaseCaptured)
				{
					((Component)gameplayCamera).transform.localPosition = state.CameraBaseLocalPosition;
				}
				state.CameraOffsetApplied = false;
			}
		}
	}
	internal static class VisorRig
	{
		private static bool? immersiveVisorPresent;

		public static bool IsImmersiveVisorPresent()
		{
			bool valueOrDefault = immersiveVisorPresent == true;
			if (!immersiveVisorPresent.HasValue)
			{
				valueOrDefault = Chainloader.PluginInfos.ContainsKey("ImmersiveVisor");
				immersiveVisorPresent = valueOrDefault;
			}
			return immersiveVisorPresent.Value;
		}

		public static void StickToCamera(LocalBodyState state)
		{
			if (!state.VisorReparented)
			{
				Transform localVisor = state.LocalVisor;
				Camera gameplayCamera = state.GameplayCamera;
				if (!((Object)(object)localVisor == (Object)null) && !((Object)(object)gameplayCamera == (Object)null))
				{
					localVisor.SetParent(((Component)gameplayCamera).transform, true);
					state.VisorReparented = true;
				}
			}
		}

		public static void Restore(LocalBodyState state)
		{
			if (state.VisorReparented)
			{
				if ((Object)(object)state.LocalVisor != (Object)null && state.VisorOriginalParentCaptured)
				{
					state.LocalVisor.SetParent(state.VisorOriginalParent, true);
				}
				state.VisorReparented = false;
			}
		}

		public static void SuppressVanillaCrack(LocalBodyState state, bool hide)
		{
			if (hide == state.CrackHidden)
			{
				return;
			}
			if (state.CrackRenderers == null)
			{
				GameObject val = (((Object)(object)HUDManager.Instance != (Object)null) ? HUDManager.Instance.visorCracksObject : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				state.CrackRenderers = val.GetComponentsInChildren<Renderer>(true);
			}
			Renderer[] crackRenderers = state.CrackRenderers;
			foreach (Renderer val2 in crackRenderers)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					val2.enabled = !hide;
				}
			}
			state.CrackHidden = hide;
		}
	}
	public static class ConfigManager
	{
		public static ConfigEntry<HeldItemFadeMode> HeldItemFadeStyle;

		public static ConfigEntry<HandsMode> Hands;

		public static ConfigEntry<ItemDitherMode> ItemDither;

		public static ConfigEntry<float> HandOffsetZ;

		public static ConfigEntry<bool> DisableHeadBob;

		public static ConfigEntry<bool> EnableMoreCompanyCompatibility;

		public static ConfigEntry<bool> EnableTooManyEmotesCompatibility;

		public static ConfigEntry<bool> ShowMoreCompanyHat;

		public static ConfigEntry<bool> ShowMoreCompanyChest;

		public static ConfigEntry<bool> ShowMoreCompanyHip;

		public static ConfigEntry<bool> ShowMoreCompanyRightLowerArm;

		public static ConfigEntry<bool> ShowMoreCompanyLeftShin;

		public static ConfigEntry<bool> ShowMoreCompanyRightShin;

		internal static void Initialize(ConfigFile config)
		{
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Expected O, but got Unknown
			EnableMoreCompanyCompatibility = config.Bind<bool>("1. Compatibility", "Enable MoreCompany Compatibility", true, "Show your MoreCompany cosmetics in first person when MoreCompany is installed.");
			EnableTooManyEmotesCompatibility = config.Bind<bool>("1. Compatibility", "Enable TooManyEmotes Compatibility", true, "Keep the camera on your head during a TooManyEmotes first-person emote. Takes effect on restart.");
			ShowMoreCompanyHat = config.Bind<bool>("1. Compatibility", "ShowHat", false, "Show hat cosmetics. False by default to prevent hats from clipping into the camera.");
			ShowMoreCompanyChest = config.Bind<bool>("1. Compatibility", "ShowChest", true, "Show chest cosmetics.");
			ShowMoreCompanyHip = config.Bind<bool>("1. Compatibility", "ShowHip", true, "Show hip cosmetics.");
			ShowMoreCompanyRightLowerArm = config.Bind<bool>("1. Compatibility", "ShowRightLowerArm", true, "Show right lower arm cosmetics.");
			ShowMoreCompanyLeftShin = config.Bind<bool>("1. Compatibility", "ShowLeftShin", true, "Show left shin cosmetics.");
			ShowMoreCompanyRightShin = config.Bind<bool>("1. Compatibility", "ShowRightShin", true, "Show right shin cosmetics.");
			HeldItemFadeStyle = config.Bind<HeldItemFadeMode>("2. Held Item", "FadeMode", HeldItemFadeMode.Dither, "Held item will start to dither when it is close to or filling the players camera. Dither: a fade that lets you see through the item. Off: nothing dithers.");
			ItemDither = config.Bind<ItemDitherMode>("2. Held Item", "ItemDither", ItemDitherMode.ThirdPerson, "Which hands mode the held item dithers in.");
			HandOffsetZ = config.Bind<float>("2. Held Item", "HandOffsetZ", 0f, new ConfigDescription("First-person hand offset.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), Array.Empty<object>()));
			Hands = config.Bind<HandsMode>("3. Hands", "HandsMode", HandsMode.Vanilla, "Which arms hold an item in first person. Vanilla: real first-person arms that aim the item with the camera [ recommended ]. ThirdPerson: the body own arms hold the item, more consistent body, but with known issues.");
			DisableHeadBob = config.Bind<bool>("4. Camera", "DisableHeadBob", false, "Disable head bobbing from walking and running animations.");
		}
	}
	internal static class Constants
	{
		public const string ScavengerModelName = "ScavengerModel";

		public const string MetarigName = "metarig";

		public const string HeadBoneName = "spine.004";

		public const string LeftArmBoneName = "shoulder.L";

		public const string RightArmBoneName = "shoulder.R";

		public const int EnemiesNotRenderedLayer = 23;

		public static readonly string[] HeadBoneNameHints = new string[4] { "head", "helmet", "visor", "spine.004" };

		public const float HeadStrongInfluenceThreshold = 0.35f;

		public const float HeadAverageInfluenceThreshold = 0.3f;

		public const float PipeCullBehindThreshold = 0f;

		public const float CrouchBlendTime = 0.15f;

		public const float LadderBlendTime = 0.08f;

		public const float BobDampBlendTime = 0.12f;

		public const float BobStabilizeTau = 0.2f;

		public const float DisableHeadBobTau = 1f;

		public const float DisableHeadBobBlendTime = 0.15f;

		public const float NeckGuardCalmTau = 0.015f;

		public const float NeckGuardSwingTau = 0.12f;

		public const float NeckGuardSwingTail = 0.6f;

		public const float NeckGuardReleaseRamp = 0.8f;

		public const float NeckGuardUpFollow = 1f;

		public const float NeckGuardDownFollow = 0f;

		public const float NeckGuardCrouchSettled = 0.9f;

		public const float NeckGuardCrouchFloor = 0.35f;

		public const float FollowStrengthVertical = 1f;

		public const float FollowStrengthHorizontal = 1f;

		public const float SprintBobReduction = 0.6f;

		public const float MaxFollowOffset = 0.5f;

		public const float EyeOffsetForward = 0.13f;

		public const float EyeOffsetForwardOnLadder = 0f;

		public const float EyeOffsetUp = 0f;

		public const float EyeOffsetRight = 0f;

		public const float CrouchEyeOffsetUp = 0.12f;

		public const float HoldingEyeOffsetForward = 0.15f;

		public const float HoldingEyeOffsetUp = 0.07f;

		public const float HoldingBlendTime = 0.18f;

		public const float RunningEyeOffsetForward = 0.1f;

		public const float RunningEyeOffsetUp = 0.05f;

		public const float RunningBlendTime = 0.18f;

		public const float JumpingEyeOffsetForward = 0.13f;

		public const float JumpingEyeOffsetUp = 0f;

		public const float JumpingBlendTime = 0.18f;

		public const bool EnableWallCollision = true;

		public const float WallCollisionRadius = 0.11f;

		public const float HeldItemFadeStartDistance = 0.35f;

		public const float HeldItemFadeEndDistance = 0.1f;

		public const float HeldItemCoverageFadeStart = 0.45f;

		public const float HeldItemCoverageFadeFull = 0.6f;

		public const float HeldItemMinFade = 0.11f;

		public const float HeldItemFadeSmoothTime = 0.08f;

		public const float SeatedLookDownClamp = 75f;

		public static readonly Vector3 CruiserKeyPositionOffset = new Vector3(0f, 0f, -0.05f);

		public static readonly Vector3 CruiserKeyRotationOffset = Vector3.zero;
	}
	public enum HandsMode
	{
		Vanilla,
		ThirdPerson
	}
	public enum HeldItemFadeMode
	{
		Dither,
		Off
	}
	[Flags]
	public enum ItemDitherMode
	{
		Vanilla = 1,
		ThirdPerson = 2
	}
	internal sealed class LocalBodyState
	{
		public PlayerControllerB Player;

		public Transform ModelRoot;

		public Transform? HeadBone;

		public SkinnedMeshRenderer? BodyRenderer;

		public Mesh? OriginalBodyMesh;

		public bool OriginalBodyMeshCaptured;

		public bool HeadHidden;

		public SkinnedMeshRenderer? ShadowProxy;

		public Transform? LeftArmBone;

		public Transform? RightArmBone;

		public Transform? LocalVisor;

		public Transform? VisorOriginalParent;

		public bool VisorOriginalParentCaptured;

		public bool VisorReparented;

		public Renderer[]? CrackRenderers;

		public bool CrackHidden;

		public Camera? GameplayCamera;

		public Vector3 CameraBaseLocalPosition;

		public bool CameraBaseCaptured;

		public bool CameraOffsetApplied;

		public Vector3 LastCameraTargetLocal;

		public bool HasCameraTarget;

		public float CrouchBlend;

		public float LadderBlend;

		public float BobDampBlend;

		public float HoldBlend;

		public float RunBlend;

		public float JumpBlend;

		public Vector3 SmoothedDeviationLocal;

		public bool DeviationSmoothInitialized;

		public float DisableBobSmoothedY;

		public bool DisableBobSmoothInitialized;

		public float DisableBobBlend;

		public Vector3 SwingRest;

		public Vector3 GuardedEyeDeviation;

		public Vector3 GuardedEyeVelocity;

		public float NeckGuardTail;

		public float NeckGuardRelease;

		public float NeckGuardFloorZ;

		public float NeckGuardCrouchRestZ;

		public float NeckGuardCrouchRestY;

		public bool NeckGuardFloorActive;

		public bool NeckGuardInitialized;

		public bool NeckGuardLatched;

		public bool NeckGuardWasSwinging;

		public bool NeckGuardEngaged;

		public Vector3 EyeAnchorLocal;

		public Vector3 EyeAnchorBoneLocal;

		public bool EyeAnchorCaptured;
	}
	internal static class LocalBodyViewController
	{
		private static readonly Dictionary<int, LocalBodyState> States = new Dictionary<int, LocalBodyState>();

		private static bool renderCallbacksHooked;

		internal static bool LocalBodyShown;

		private static readonly (Action<Camera> Apply, Action<Camera> Restore)[] CameraPasses = new(Action<Camera>, Action<Camera>)[2]
		{
			(FirstPersonBody.ApplyForCamera, FirstPersonBody.RestoreAfterCamera),
			(HeldItemView.ApplyForCamera, HeldItemView.RestoreAfterCamera)
		};

		public static void ResetAllStates()
		{
			foreach (LocalBodyState value in States.Values)
			{
				FirstPersonBody.RestoreHead(value);
				VisorRig.Restore(value);
				CameraRig.RestoreOffset(value);
				if ((Object)(object)value.ShadowProxy != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)value.ShadowProxy).gameObject);
				}
			}
			States.Clear();
			LocalBodyShown = false;
			FirstPersonBody.Reset();
			HeldItemView.Reset();
			MeshSurgery.ClearCaches();
			if (renderCallbacksHooked)
			{
				RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering;
				RenderPipelineManager.endCameraRendering -= OnEndCameraRendering;
				renderCallbacksHooked = false;
			}
		}

		public static void Tick(PlayerControllerB player)
		{
			if (Players.IsLocal(player))
			{
				EnsureRenderCallbacksHooked();
				LocalBodyState orCreateState = GetOrCreateState(player);
				if (NeedsRefresh(orCreateState, player))
				{
					RefreshState(orCreateState, player);
				}
				bool flag = (LocalBodyShown = player.isPlayerControlled && !player.isPlayerDead);
				bool flag2 = flag && Players.IsActivelyHolding(player) && !player.inSpecialInteractAnimation && ConfigManager.Hands.Value == HandsMode.Vanilla;
				FirstPersonBody.ApplyBodyRendering(orCreateState, flag, flag2);
				FirstPersonBody.ApplyFirstPersonCameraLayer(orCreateState, flag);
				HeldItemView.ApplyHolder(orCreateState, player, flag, flag2);
				if (flag)
				{
					FirstPersonBody.HideHead(orCreateState, flag2);
				}
				else
				{
					FirstPersonBody.RestoreHead(orCreateState);
				}
				if (flag && !VisorRig.IsImmersiveVisorPresent())
				{
					VisorRig.StickToCamera(orCreateState);
				}
				else
				{
					VisorRig.Restore(orCreateState);
				}
				VisorRig.SuppressVanillaCrack(orCreateState, VisorRig.IsImmersiveVisorPresent());
				if (flag && !player.inTerminalMenu)
				{
					CameraRig.ApplyOffset(orCreateState, player);
				}
				else
				{
					CameraRig.RestoreOffset(orCreateState);
				}
				CameraRig.ApplyArmAnchor(player, flag2);
				CameraRig.RelaxSeatedLookClamp(player);
				MoreCompanyCompat.ApplyLocalCosmeticVisibility(player, flag, flag2);
			}
		}

		public static void AlignCameraForInteractionRay(PlayerControllerB player)
		{
			if (Players.IsLocal(player) && States.TryGetValue(((Object)player).GetInstanceID(), out LocalBodyState value))
			{
				CameraRig.AlignForInteractionRay(value);
			}
		}

		private static LocalBodyState GetOrCreateState(PlayerControllerB player)
		{
			int instanceID = ((Object)player).GetInstanceID();
			if (!States.TryGetValue(instanceID, out LocalBodyState value))
			{
				value = new LocalBodyState();
				States[instanceID] = value;
			}
			return value;
		}

		private static bool NeedsRefresh(LocalBodyState state, PlayerControllerB player)
		{
			if (!((Object)(object)state.Player != (Object)(object)player) && !((Object)(object)state.ModelRoot == (Object)null) && !((Object)(object)state.HeadBone == (Object)null))
			{
				return (Object)(object)state.BodyRenderer == (Object)null;
			}
			return true;
		}

		private static void RefreshState(LocalBodyState state, PlayerControllerB player)
		{
			state.Player = player;
			Transform val = ((Component)player).transform.Find("ScavengerModel");
			state.ModelRoot = (((Object)(object)val != (Object)null) ? val : ((Component)player).transform);
			state.HeadBone = FindHeadBone(state.ModelRoot, player);
			state.LeftArmBone = FindBodyBone(player, "shoulder.L");
			state.RightArmBone = FindBodyBone(player, "shoulder.R");
			state.BodyRenderer = player.thisPlayerModel;
			CaptureOriginalBodyMesh(state);
			state.LocalVisor = player.localVisor;
			CaptureVisorOriginalParent(state);
			state.GameplayCamera = player.gameplayCamera;
			CaptureCameraBase(state);
		}

		private static void CaptureOriginalBodyMesh(LocalBodyState state)
		{
			if (!((Object)(object)state.BodyRenderer == (Object)null) && !state.OriginalBodyMeshCaptured && !state.HeadHidden)
			{
				Mesh sharedMesh = state.BodyRenderer.sharedMesh;
				if (!((Object)(object)sharedMesh == (Object)null) && !MeshSurgery.IsGenerated(((Object)sharedMesh).GetInstanceID()))
				{
					state.OriginalBodyMesh = sharedMesh;
					state.OriginalBodyMeshCaptured = true;
				}
			}
		}

		private static void CaptureVisorOriginalParent(LocalBodyState state)
		{
			if (!((Object)(object)state.LocalVisor == (Object)null) && !state.VisorOriginalParentCaptured && !state.VisorReparented)
			{
				state.VisorOriginalParent = state.LocalVisor.parent;
				state.VisorOriginalParentCaptured = true;
			}
		}

		private static void CaptureCameraBase(LocalBodyState state)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)state.GameplayCamera == (Object)null) && !state.CameraBaseCaptured && !state.CameraOffsetApplied)
			{
				state.CameraBaseLocalPosition = ((Component)state.GameplayCamera).transform.localPosition;
				state.CameraBaseCaptured = true;
			}
		}

		private static Transform? FindHeadBone(Transform modelRoot, PlayerControllerB player)
		{
			SkinnedMeshRenderer thisPlayerModel = player.thisPlayerModel;
			if ((Object)(object)thisPlayerModel != (Object)null)
			{
				Transform[] bones = thisPlayerModel.bones;
				foreach (Transform val in bones)
				{
					if ((Object)(object)val != (Object)null && NameContains(((Object)val).name, "spine.004"))
					{
						return val;
					}
				}
			}
			return FindFirstByNameContains(modelRoot, "spine.004") ?? FindFirstByNameContains(modelRoot, "head");
		}

		private static Transform? FindBodyBone(PlayerControllerB player, string boneName)
		{
			SkinnedMeshRenderer thisPlayerModel = player.thisPlayerModel;
			if ((Object)(object)thisPlayerModel == (Object)null)
			{
				return null;
			}
			Transform[] bones = thisPlayerModel.bones;
			foreach (Transform val in bones)
			{
				if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, boneName, StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return null;
		}

		private static Transform? FindFirstByNameContains(Transform root, string token)
		{
			Queue<Transform> queue = new Queue<Transform>();
			queue.Enqueue(root);
			while (queue.Count > 0)
			{
				Transform val = queue.Dequeue();
				if (NameContains(((Object)val).name, token))
				{
					return val;
				}
				for (int i = 0; i < val.childCount; i++)
				{
					queue.Enqueue(val.GetChild(i));
				}
			}
			return null;
		}

		private static bool NameContains(string name, string token)
		{
			return name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static void EnsureRenderCallbacksHooked()
		{
			if (!renderCallbacksHooked)
			{
				renderCallbacksHooked = true;
				RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
				RenderPipelineManager.endCameraRendering += OnEndCameraRendering;
			}
		}

		private static void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
		{
			(Action<Camera>, Action<Camera>)[] cameraPasses = CameraPasses;
			for (int i = 0; i < cameraPasses.Length; i++)
			{
				(Action<Camera>, Action<Camera>) tuple = cameraPasses[i];
				tuple.Item1(camera);
			}
		}

		private static void OnEndCameraRendering(ScriptableRenderContext context, Camera camera)
		{
			(Action<Camera>, Action<Camera>)[] cameraPasses = CameraPasses;
			for (int i = 0; i < cameraPasses.Length; i++)
			{
				(Action<Camera>, Action<Camera>) tuple = cameraPasses[i];
				tuple.Item2(camera);
			}
		}
	}
	internal static class ModGUIDs
	{
		public const string MoreCompany = "me.swipez.melonloader.morecompany";

		public const string TooManyEmotes = "FlipMods.TooManyEmotes";

		public const string ImmersiveVisor = "ImmersiveVisor";
	}
	internal static class Players
	{
		public static bool IsLocal(PlayerControllerB player)
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				return (Object)(object)instance.localPlayerController == (Object)(object)player;
			}
			return false;
		}

		public static bool IsActivelyHolding(PlayerControllerB player)
		{
			GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer;
			if ((Object)(object)currentlyHeldObjectServer != (Object)null && currentlyHeldObjectServer.isHeld && !currentlyHeldObjectServer.isPocketed)
			{
				return (Object)(object)currentlyHeldObjectServer.playerHeldBy == (Object)(object)player;
			}
			return false;
		}

		public static bool IsHoldingTwoHanded(PlayerControllerB player)
		{
			return player.twoHanded;
		}
	}
	[BepInPlugin("com.seeya.firstpersonview", "First-Person View", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private readonly Harmony _harmony = new Harmony("com.seeya.firstpersonview");

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		internal static Harmony Harmony { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Harmony = _harmony;
			Log.LogInfo((object)"Initializing First-Person View");
			ConfigManager.Initialize(((BaseUnityPlugin)this).Config);
			MoreCompanyCompat.Initialize();
			TooManyEmotesCompat.Initialize();
			_harmony.PatchAll();
			Log.LogInfo((object)"First-Person View is loaded!");
		}
	}
	internal static class FirstPersonBody
	{
		private static SkinnedMeshRenderer? hideRenderer;

		private static Mesh? originalMesh;

		private static Mesh? headlessMesh;

		private static Mesh? headlessArmlessMesh;

		private static bool hideArmsInFirstPerson;

		private static Camera? hideCamera;

		private static bool hideActive;

		private static SkinnedMeshRenderer? fpArms;

		private static bool fpArmsIntended;

		public static void ApplyBodyRendering(LocalBodyState state, bool showBody, bool useVanillaArms)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Invalid comparison between Unknown and I4
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Invalid comparison between Unknown and I4
			PlayerControllerB player = state.Player;
			if ((Object)(object)player == (Object)null || !player.isPlayerControlled || player.isPlayerDead)
			{
				return;
			}
			if (showBody)
			{
				if ((Object)(object)player.thisPlayerModel != (Object)null)
				{
					if (!((Renderer)player.thisPlayerModel).enabled)
					{
						((Renderer)player.thisPlayerModel).enabled = true;
					}
					if ((int)((Renderer)player.thisPlayerModel).shadowCastingMode != 1)
					{
						((Renderer)player.thisPlayerModel).shadowCastingMode = (ShadowCastingMode)1;
					}
				}
				if ((Object)(object)player.thisPlayerModelLOD1 != (Object)null && ((Renderer)player.thisPlayerModelLOD1).enabled)
				{
					((Renderer)player.thisPlayerModelLOD1).enabled = false;
				}
				if ((Object)(object)player.thisPlayerModelLOD2 != (Object)null && ((Renderer)player.thisPlayerModelLOD2).enabled)
				{
					((Renderer)player.thisPlayerModelLOD2).enabled = false;
				}
				SetFpArmsEnabled(player, useVanillaArms);
			}
			else
			{
				if ((Object)(object)player.thisPlayerModel != (Object)null && (int)((Renderer)player.thisPlayerModel).shadowCastingMode != 3)
				{
					((Renderer)player.thisPlayerModel).shadowCastingMode = (ShadowCastingMode)3;
				}
				SetFpArmsEnabled(player, enabled: true);
			}
		}

		private static void SetFpArmsEnabled(PlayerControllerB player, bool enabled)
		{
			fpArms = player.thisPlayerModelArms;
			fpArmsIntended = enabled;
			if ((Object)(object)fpArms != (Object)null && ((Renderer)fpArms).enabled != enabled)
			{
				((Renderer)fpArms).enabled = enabled;
			}
		}

		public static void ApplyFirstPersonCameraLayer(LocalBodyState state, bool showBody)
		{
			Camera gameplayCamera = state.GameplayCamera;
			if (!((Object)(object)gameplayCamera == (Object)null))
			{
				int num = 8388608;
				bool flag = (gameplayCamera.cullingMask & num) != 0;
				if (showBody && !flag)
				{
					gameplayCamera.cullingMask |= num;
				}
				else if (!showBody && flag)
				{
					gameplayCamera.cullingMask &= ~num;
				}
			}
		}

		public static void HideHead(LocalBodyState state, bool hideArms)
		{
			hideArmsInFirstPerson = hideArms;
			state.HeadHidden = true;
			SkinnedMeshRenderer bodyRenderer = state.BodyRenderer;
			Mesh originalBodyMesh = state.OriginalBodyMesh;
			if ((Object)(object)bodyRenderer == (Object)null || (Object)(object)originalBodyMesh == (Object)null || (Object)(object)state.HeadBone == (Object)null)
			{
				hideActive = false;
				UpdateShadowProxy(state, active: false);
				return;
			}
			Mesh orCreateHeadlessMesh = MeshSurgery.GetOrCreateHeadlessMesh(originalBodyMesh, bodyRenderer, state.HeadBone);
			if ((Object)(object)orCreateHeadlessMesh == (Object)null)
			{
				hideActive = false;
				UpdateShadowProxy(state, active: false);
				return;
			}
			if ((Object)(object)bodyRenderer.sharedMesh != (Object)(object)originalBodyMesh)
			{
				bodyRenderer.sharedMesh = originalBodyMesh;
			}
			headlessArmlessMesh = (hideArms ? MeshSurgery.GetOrCreateHeadlessArmlessMesh(originalBodyMesh, bodyRenderer, state.HeadBone, state.LeftArmBone, state.RightArmBone) : null);
			hideRenderer = bodyRenderer;
			originalMesh = originalBodyMesh;
			headlessMesh = orCreateHeadlessMesh;
			hideCamera = state.GameplayCamera;
			hideActive = true;
			UpdateShadowProxy(state, active: true);
		}

		public static void RestoreHead(LocalBodyState state)
		{
			hideActive = false;
			SkinnedMeshRenderer bodyRenderer = state.BodyRenderer;
			if ((Object)(object)bodyRenderer != (Object)null && (Object)(object)state.OriginalBodyMesh != (Object)null && (Object)(object)bodyRenderer.sharedMesh != (Object)(object)state.OriginalBodyMesh)
			{
				bodyRenderer.sharedMesh = state.OriginalBodyMesh;
			}
			UpdateShadowProxy(state, active: false);
			state.HeadHidden = false;
		}

		private static void UpdateShadowProxy(LocalBodyState state, bool active)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_007e: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			if (!active)
			{
				if ((Object)(object)state.ShadowProxy != (Object)null)
				{
					((Renderer)state.ShadowProxy).enabled = false;
				}
				return;
			}
			SkinnedMeshRenderer bodyRenderer = state.BodyRenderer;
			Mesh originalBodyMesh = state.OriginalBodyMesh;
			if ((Object)(object)bodyRenderer == (Object)null || (Object)(object)originalBodyMesh == (Object)null)
			{
				return;
			}
			if ((Object)(object)state.ShadowProxy == (Object)null)
			{
				try
				{
					GameObject val = new GameObject("FPVHeadShadowProxy");
					val.transform.SetParent(((Component)bodyRenderer).transform.parent, false);
					val.transform.localPosition = ((Component)bodyRenderer).transform.localPosition;
					val.transform.localRotation = ((Component)bodyRenderer).transform.localRotation;
					val.transform.localScale = ((Component)bodyRenderer).transform.localScale;
					SkinnedMeshRenderer val2 = val.AddComponent<SkinnedMeshRenderer>();
					val2.sharedMesh = originalBodyMesh;
					val2.bones = bodyRenderer.bones;
					val2.rootBone = bodyRenderer.rootBone;
					((Renderer)val2).sharedMaterials = ((Renderer)bodyRenderer).sharedMaterials;
					((Renderer)val2).shadowCastingMode = (ShadowCastingMode)3;
					val2.updateWhenOffscreen = true;
					state.ShadowProxy = val2;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Failed to create head shadow proxy. " + ex.Message));
					return;
				}
			}
			((Component)state.ShadowProxy).gameObject.layer = ((Component)bodyRenderer).gameObject.layer;
			if (!((Renderer)state.ShadowProxy).enabled)
			{
				((Renderer)state.ShadowProxy).enabled = true;
			}
		}

		public static void ApplyForCamera(Camera camera)
		{
			SkinnedMeshRenderer val = hideRenderer;
			if (!hideActive || (Object)(object)val == (Object)null)
			{
				return;
			}
			if ((Object)(object)camera == (Object)(object)hideCamera)
			{
				Mesh val2 = ((hideArmsInFirstPerson && (Object)(object)headlessArmlessMesh != (Object)null) ? headlessArmlessMesh : headlessMesh);
				if ((Object)(object)val2 != (Object)null && (Object)(object)val.sharedMesh != (Object)(object)val2)
				{
					val.sharedMesh = val2;
				}
			}
			else if ((Object)(object)originalMesh != (Object)null && (Object)(object)val.sharedMesh != (Object)(object)originalMesh)
			{
				val.sharedMesh = originalMesh;
			}
			if ((Object)(object)fpArms != (Object)null)
			{
				((Renderer)fpArms).enabled = fpArmsIntended && (Object)(object)camera == (Object)(object)hideCamera;
			}
		}

		public static void RestoreAfterCamera(Camera camera)
		{
			if ((Object)(object)fpArms != (Object)null && ((Renderer)fpArms).enabled != fpArmsIntended)
			{
				((Renderer)fpArms).enabled = fpArmsIntended;
			}
			SkinnedMeshRenderer val = hideRenderer;
			if (!((Object)(object)val == (Object)null) && !((Object)(object)originalMesh == (Object)null) && (Object)(object)camera == (Object)(object)hideCamera && (Object)(object)val.sharedMesh != (Object)(object)originalMesh)
			{
				val.sharedMesh = originalMesh;
			}
		}

		public static void Reset()
		{
			hideActive = false;
			hideRenderer = null;
			originalMesh = null;
			headlessMesh = null;
			headlessArmlessMesh = null;
			hideArmsInFirstPerson = false;
			hideCamera = null;
			fpArms = null;
			fpArmsIntended = false;
		}
	}
	internal static class HeldItemView
	{
		private const int CoverageGridSize = 16;

		private static readonly int[] coverageRowMin = new int[16];

		private static readonly int[] coverageRowMax = new int[16];

		private static GrabbableObject? trackedItem;

		private static Renderer[] renderers = Array.Empty<Renderer>();

		private static MotionVectorGenerationMode[] originalMotionModes = Array.Empty<MotionVectorGenerationMode>();

		private static Material[] materials = Array.Empty<Material>();

		private static Renderer? boundsSource;

		private static Vector3[] localVertices = Array.Empty<Vector3>();

		private static Camera? camera;

		private static bool hideActive;

		private static float fadeCurrent = 1f;

		private static bool fpItemActive;

		private static Transform? localHolder;

		private static Transform? serverHolder;

		private static Transform? itemTransform;

		private static bool itemRepositioned;

		private static Vector3 cachedItemPos;

		private static Quaternion cachedItemRot;

		public static void ApplyHolder(LocalBodyState state, PlayerControllerB player, bool showBody, bool useVanillaArms)
		{
			GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer;
			bool flag = Players.IsActivelyHolding(player);
			bool isInspectingItem = player.IsInspectingItem;
			if (flag && (Object)(object)currentlyHeldObjectServer != (Object)null)
			{
				Transform val = ((useVanillaArms || isInspectingItem || !showBody) ? player.localItemHolder : player.serverItemHolder);
				if ((Object)(object)val != (Object)null && (Object)(object)currentlyHeldObjectServer.parentObject != (Object)(object)val)
				{
					currentlyHeldObjectServer.parentObject = val;
				}
			}
			bool flag2 = DitherEnabled();
			GrabbableObject val2 = (flag ? currentlyHeldObjectServer : null);
			if ((Object)(object)val2 != (Object)(object)trackedItem)
			{
				ResetEffect();
				RestoreMotionVectors();
				trackedItem = val2;
				renderers = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponentsInChildren<Renderer>() : Array.Empty<Renderer>());
				SuppressMotionVectors();
				materials = (Material[])(flag2 ? ((Array)MaterialDither.CollectInstancedMaterials(renderers)) : ((Array)Array.Empty<Material>()));
				boundsSource = ResolveBoundsSource(val2, renderers);
				localVertices = ResolveLocalVertices(boundsSource);
			}
			else if (flag2 && materials.Length == 0 && renderers.Length != 0)
			{
				materials = MaterialDither.CollectInstancedMaterials(renderers);
			}
			camera = state.GameplayCamera;
			hideActive = showBody && (Object)(object)val2 != (Object)null && !isInspectingItem;
			bool flag3 = (fpItemActive = useVanillaArms && showBody && flag && !isInspectingItem && (Object)(object)currentlyHeldObjectServer != (Object)null);
			localHolder = player.localItemHolder;
			serverHolder = player.serverItemHolder;
			itemTransform = (flag3 ? ((Component)currentlyHeldObjectServer).transform : null);
		}

		public static void ApplyForCamera(Camera renderingCamera)
		{
			RepositionForCamera(renderingCamera);
			if (hideActive && renderers.Length != 0 && DitherEnabled())
			{
				float fade = (((Object)(object)renderingCamera == (Object)(object)camera) ? ComputeFade(renderingCamera) : 1f);
				ApplyFade(fade);
			}
		}

		private static void RepositionForCamera(Camera renderingCamera)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (fpItemActive && !itemRepositioned && !((Object)(object)itemTransform == (Object)null) && !((Object)(object)localHolder == (Object)null) && !((Object)(object)serverHolder == (Object)null) && !((Object)(object)renderingCamera == (Object)(object)camera))
			{
				cachedItemPos = itemTransform.position;
				cachedItemRot = itemTransform.rotation;
				Vector3 val = localHolder.InverseTransformPoint(cachedItemPos);
				Quaternion val2 = Quaternion.Inverse(localHolder.rotation) * cachedItemRot;
				itemTransform.position = serverHolder.TransformPoint(val);
				itemTransform.rotation = serverHolder.rotation * val2;
				itemRepositioned = true;
			}
		}

		private static bool DitherEnabled()
		{
			if (ConfigManager.HeldItemFadeStyle.Value == HeldItemFadeMode.Off)
			{
				return false;
			}
			ItemDitherMode value = ConfigManager.ItemDither.Value;
			if (ConfigManager.Hands.Value != HandsMode.Vanilla)
			{
				return (value & ItemDitherMode.ThirdPerson) != 0;
			}
			return (value & ItemDitherMode.Vanilla) != 0;
		}

		public static void RestoreAfterCamera(Camera renderingCamera)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (itemRepositioned && (Object)(object)itemTransform != (Object)null)
			{
				itemTransform.position = cachedItemPos;
				itemTransform.rotation = cachedItemRot;
			}
			itemRepositioned = false;
			if (renderers.Length != 0 && (Object)(object)renderingCamera == (Object)(object)camera)
			{
				ApplyFade(1f);
			}
		}

		private static float ComputeFade(Camera renderingCamera)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			Renderer val = boundsSource;
			if ((Object)(object)val == (Object)null)
			{
				return 1f;
			}
			Vector3[] array = localVertices;
			Vector3 position = ((Component)renderingCamera).transform.position;
			float num;
			if (array.Length == 0)
			{
				num = MaterialDither.ProximityFade(NearestBoxDistance(val, position));
			}
			else
			{
				Matrix4x4 localToWorldMatrix = val.localToWorldMatrix;
				float num2 = float.MaxValue;
				for (int i = 0; i < 16; i++)
				{
					coverageRowMin[i] = 16;
					coverageRowMax[i] = -1;
				}
				Vector3[] array2 = array;
				foreach (Vector3 val2 in array2)
				{
					Vector3 val3 = ((Matrix4x4)(ref localToWorldMatrix)).MultiplyPoint3x4(val2);
					Vector3 val4 = val3 - position;
					float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude;
					if (sqrMagnitude < num2)
					{
						num2 = sqrMagnitude;
					}
					Vector3 val5 = renderingCamera.WorldToViewportPoint(val3);
					if (!(val5.z <= 0f))
					{
						int num3 = Mathf.Clamp((int)(Mathf.Clamp01(val5.x) * 16f), 0, 15);
						int num4 = Mathf.Clamp((int)(Mathf.Clamp01(val5.y) * 16f), 0, 15);
						if (num3 < coverageRowMin[num4])
						{
							coverageRowMin[num4] = num3;
						}
						if (num3 > coverageRowMax[num4])
						{
							coverageRowMax[num4] = num3;
						}
					}
				}
				int num5 = 0;
				for (int k = 0; k < 16; k++)
				{
					if (coverageRowMax[k] >= coverageRowMin[k])
					{
						num5 += coverageRowMax[k] - coverageRowMin[k] + 1;
					}
				}
				float coverage = (float)num5 / 256f;
				num = Mathf.Min(MaterialDither.ProximityFade(Mathf.Sqrt(num2)), CoverageFade(coverage));
			}
			num = Mathf.Max(0.11f, num);
			fadeCurrent = MaterialDither.Smooth(fadeCurrent, num, 0.08f);
			return fadeCurrent;
		}

		private static float CoverageFade(float coverage)
		{
			return 1f - Mathf.Clamp01(Mathf.InverseLerp(0.45f, 0.6f, coverage));
		}

		private static float NearestBoxDistance(Renderer renderer, Vector3 worldPoint)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			Matrix4x4 val = renderer.worldToLocalMatrix;
			Vector3 val2 = ((Matrix4x4)(ref val)).MultiplyPoint3x4(worldPoint);
			Bounds localBounds = renderer.localBounds;
			Vector3 val3 = ((Bounds)(ref localBounds)).ClosestPoint(val2);
			val = renderer.localToWorldMatrix;
			Vector3 val4 = ((Matrix4x4)(ref val)).MultiplyPoint3x4(val3);
			return Vector3.Distance(worldPoint, val4);
		}

		private static Vector3[] ResolveLocalVertices(Renderer? source)
		{
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((source is SkinnedMeshRenderer) ? source : null);
			Mesh val2;
			if (val == null)
			{
				if (source == null)
				{
					val2 = null;
				}
				else
				{
					MeshFilter component = ((Component)source).GetComponent<MeshFilter>();
					val2 = ((component != null) ? component.sharedMesh : null);
				}
			}
			else
			{
				val2 = val.sharedMesh;
			}
			Mesh val3 = val2;
			if (!((Object)(object)val3 != (Object)null) || !val3.isReadable)
			{
				return Array.Empty<Vector3>();
			}
			return val3.vertices;
		}

		private static Renderer? ResolveBoundsSource(GrabbableObject? item, Renderer[] itemRenderers)
		{
			if ((Object)(object)item == (Object)null)
			{
				return null;
			}
			if ((Object)(object)item.mainObjectRenderer != (Object)null)
			{
				return (Renderer?)(object)item.mainObjectRenderer;
			}
			foreach (Renderer val in itemRenderers)
			{
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private static void ApplyFade(float fade)
		{
			MaterialDither.Set(renderers, materials, fade);
		}

		private static void ResetEffect()
		{
			MaterialDither.Set(renderers, materials, 1f);
			fadeCurrent = 1f;
		}

		private static void SuppressMotionVectors()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected I4, but got Unknown
			originalMotionModes = (MotionVectorGenerationMode[])((renderers.Length != 0) ? ((Array)new MotionVectorGenerationMode[renderers.Length]) : ((Array)Array.Empty<MotionVectorGenerationMode>()));
			for (int i = 0; i < renderers.Length; i++)
			{
				Renderer val = renderers[i];
				if (!((Object)(object)val == (Object)null))
				{
					originalMotionModes[i] = (MotionVectorGenerationMode)(int)val.motionVectorGenerationMode;
					val.motionVectorGenerationMode = (MotionVectorGenerationMode)2;
				}
			}
		}

		private static void RestoreMotionVectors()
		{
			for (int i = 0; i < renderers.Length && i < originalMotionModes.Length; i++)
			{
				Renderer val = renderers[i];
				if ((Object)(object)val != (Object)null)
				{
					val.motionVectorGenerationMode = originalMotionModes[i];
				}
			}
			originalMotionModes = Array.Empty<MotionVectorGenerationMode>();
		}

		public static void Reset()
		{
			ResetEffect();
			RestoreMotionVectors();
			trackedItem = null;
			renderers = Array.Empty<Renderer>();
			materials = Array.Empty<Material>();
			boundsSource = null;
			localVertices = Array.Empty<Vector3>();
			camera = null;
			hideActive = false;
			fpItemActive = false;
			localHolder = null;
			serverHolder = null;
			itemTransform = null;
			itemRepositioned = false;
		}
	}
	internal static class MaterialDither
	{
		public const string CrossfadeKeyword = "LOD_FADE_CROSSFADE";

		public static readonly int LodFadeId = Shader.PropertyToID("unity_LODFade");

		private static MaterialPropertyBlock? scratch;

		public static Material[] CollectInstancedMaterials(params Renderer[] renderers)
		{
			if (renderers.Length == 0)
			{
				return Array.Empty<Material>();
			}
			List<Material> list = new List<Material>();
			foreach (Renderer val in renderers)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Material[] materials = val.materials;
				foreach (Material val2 in materials)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						list.Add(val2);
					}
				}
			}
			return list.ToArray();
		}

		public static void Set(Renderer[] renderers, Material[] materials, float fade)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			ToggleKeyword(materials, fade < 0.999f);
			Vector4 lodFade = default(Vector4);
			((Vector4)(ref lodFade))..ctor(fade, fade, 0f, 0f);
			foreach (Renderer renderer in renderers)
			{
				WriteFade(renderer, lodFade);
			}
		}

		public static void Set(Renderer? renderer, Material[] materials, float fade)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			ToggleKeyword(materials, fade < 0.999f);
			WriteFade(renderer, new Vector4(fade, fade, 0f, 0f));
		}

		private static void ToggleKeyword(Material[] materials, bool enable)
		{
			foreach (Material val in materials)
			{
				if (!((Object)(object)val == (Object)null))
				{
					if (enable)
					{
						val.EnableKeyword("LOD_FADE_CROSSFADE");
					}
					else
					{
						val.DisableKeyword("LOD_FADE_CROSSFADE");
					}
				}
			}
		}

		private static void WriteFade(Renderer? renderer, Vector4 lodFade)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			if (!((Object)(object)renderer == (Object)null))
			{
				if (scratch == null)
				{
					scratch = new MaterialPropertyBlock();
				}
				renderer.GetPropertyBlock(scratch);
				scratch.SetVector(LodFadeId, lodFade);
				renderer.SetPropertyBlock(scratch);
			}
		}

		public static float ProximityFade(float distance)
		{
			return Mathf.Clamp01(Mathf.InverseLerp(0.1f, 0.35f, distance));
		}

		public static float Smooth(float current, float target, float smoothTime)
		{
			float num = 1f - Mathf.Exp((0f - Time.deltaTime) / smoothTime);
			return Mathf.Lerp(current, target, num);
		}
	}
	internal static class MeshSurgery
	{
		private static readonly Dictionary<int, Mesh> HeadlessMeshCache = new Dictionary<int, Mesh>();

		private static readonly Dictionary<int, Mesh> HeadlessArmlessMeshCache = new Dictionary<int, Mesh>();

		private static readonly Dictionary<int, Mesh?> ReadableCopies = new Dictionary<int, Mesh>();

		private static readonly HashSet<int> GeneratedMeshIds = new HashSet<int>();

		private static readonly HashSet<int> LoggedUnreadableMeshes = new HashSet<int>();

		public static bool IsGenerated(int meshInstanceId)
		{
			return GeneratedMeshIds.Contains(meshInstanceId);
		}

		private static int DominantBoneIndex(BoneWeight bw)
		{
			int result = ((BoneWeight)(ref bw)).boneIndex0;
			float num = ((BoneWeight)(ref bw)).weight0;
			if (((BoneWeight)(ref bw)).weight1 > num)
			{
				num = ((BoneWeight)(ref bw)).weight1;
				result = ((BoneWeight)(ref bw)).boneIndex1;
			}
			if (((BoneWeight)(ref bw)).weight2 > num)
			{
				num = ((BoneWeight)(ref bw)).weight2;
				result = ((BoneWeight)(ref bw)).boneIndex2;
			}
			if (((BoneWeight)(ref bw)).weight3 > num)
			{
				num = ((BoneWeight)(ref bw)).weight3;
				result = ((BoneWeight)(ref bw)).boneIndex3;
			}
			if (!(num > 0f))
			{
				return -1;
			}
			return result;
		}

		private static bool[]? BuildPipeMask(Mesh mesh, SkinnedMeshRenderer skinned, Transform headBone)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = headBone.parent;
			Transform[] bones = skinned.bones;
			if ((Object)(object)parent == (Object)null || mesh.bindposes == null || mesh.bindposes.Length < bones.Length)
			{
				return null;
			}
			int num = Array.IndexOf(bones, parent);
			int num2 = Array.IndexOf(bones, headBone);
			if (num < 0 || num2 < 0)
			{
				return null;
			}
			if (!TryGetBodyForward(mesh, bones, num2, num, out var forward))
			{
				return null;
			}
			Vector3 val = BoneBindPosition(mesh, num);
			BoneWeight[] boneWeights = mesh.boneWeights;
			Vector3[] vertices = mesh.vertices;
			bool[] array = new bool[vertices.Length];
			int num3 = 0;
			for (int i = 0; i < vertices.Length; i++)
			{
				if (DominantBoneIndex(boneWeights[i]) == num && Vector3.Dot(vertices[i] - val, forward) < 0f)
				{
					array[i] = true;
					num3++;
				}
			}
			if (num3 <= 0)
			{
				return null;
			}
			return array;
		}

		private static bool TryGetBodyForward(Mesh mesh, Transform[] bones, int headIndex, int neckIndex, out Vector3 forward)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			forward = Vector3.zero;
			int num = FindBoneIndex(bones, "toe.L");
			int num2 = FindBoneIndex(bones, "heel.02.L");
			int num3 = FindBoneIndex(bones, "toe.R");
			int num4 = FindBoneIndex(bones, "heel.02.R");
			if (num < 0 || num2 < 0 || num3 < 0 || num4 < 0)
			{
				return false;
			}
			Vector3 val = BoneBindPosition(mesh, num) - BoneBindPosition(mesh, num2) + (BoneBindPosition(mesh, num3) - BoneBindPosition(mesh, num4));
			Vector3 val2 = BoneBindPosition(mesh, headIndex) - BoneBindPosition(mesh, neckIndex);
			if (((Vector3)(ref val2)).sqrMagnitude > 1E-06f)
			{
				val -= ((Vector3)(ref val2)).normalized * Vector3.Dot(val, ((Vector3)(ref val2)).normalized);
			}
			if (((Vector3)(ref val)).sqrMagnitude < 1E-06f)
			{
				return false;
			}
			forward = ((Vector3)(ref val)).normalized;
			return true;
		}

		private static Vector3 BoneBindPosition(Mesh mesh, int boneIndex)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			Matrix4x4 inverse = ((Matrix4x4)(ref mesh.bindposes[boneIndex])).inverse;
			return new Vector3(inverse.m03, inverse.m13, inverse.m23);
		}

		private static int FindBoneIndex(Transform[] bones, string boneName)
		{
			for (int i = 0; i < bones.Length; i++)
			{
				if ((Object)(object)bones[i] != (Object)null && string.Equals(((Object)bones[i]).name, boneName, StringComparison.OrdinalIgnoreCase))
				{
					return i;
				}
			}
			return -1;
		}

		public static void ClearCaches()
		{
			foreach (Mesh value in HeadlessMeshCache.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			foreach (Mesh value2 in HeadlessArmlessMeshCache.Values)
			{
				if ((Object)(object)value2 != (Object)null)
				{
					Object.Destroy((Object)(object)value2);
				}
			}
			foreach (Mesh value3 in ReadableCopies.Values)
			{
				if ((Object)(object)value3 != (Object)null)
				{
					Object.Destroy((Object)(object)value3);
				}
			}
			HeadlessMeshCache.Clear();
			HeadlessArmlessMeshCache.Clear();
			ReadableCopies.Clear();
			GeneratedMeshIds.Clear();
			LoggedUnreadableMeshes.Clear();
		}

		public static Mesh? GetOrCreateHeadlessMesh(Mesh sourceMesh, SkinnedMeshRenderer skinned, Transform headBone)
		{
			int instanceID = ((Object)sourceMesh).GetInstanceID();
			if (HeadlessMeshCache.TryGetValue(instanceID, out Mesh value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Mesh val = ResolveReadable(sourceMesh, instanceID);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			bool[] pipeMask = BuildPipeMask(val, skinned, headBone);
			Mesh val2 = TryBuildFilteredMesh(val, GetHeadBoneIndices(skinned, headBone), pipeMask, "_FPVHeadless");
			if ((Object)(object)val2 != (Object)null)
			{
				HeadlessMeshCache[instanceID] = val2;
				GeneratedMeshIds.Add(((Object)val2).GetInstanceID());
			}
			return val2;
		}

		public static Mesh? GetOrCreateHeadlessArmlessMesh(Mesh sourceMesh, SkinnedMeshRenderer skinned, Transform headBone, Transform? leftArm, Transform? rightArm)
		{
			int instanceID = ((Object)sourceMesh).GetInstanceID();
			if (HeadlessArmlessMeshCache.TryGetValue(instanceID, out Mesh value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Mesh val = ResolveReadable(sourceMesh, instanceID);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Mesh val2;
			try
			{
				val2 = BuildHeadlessArmlessMesh(val, skinned, headBone, leftArm, rightArm, "_FPVHeadlessArmless");
			}
			catch (Exception)
			{
				return null;
			}
			if ((Object)(object)val2 != (Object)null)
			{
				HeadlessArmlessMeshCache[instanceID] = val2;
				GeneratedMeshIds.Add(((Object)val2).GetInstanceID());
			}
			return val2;
		}

		private static Mesh? BuildHeadlessArmlessMesh(Mesh sourceMesh, SkinnedMeshRenderer skinned, Transform headBone, Transform? leftArm, Transform? rightArm, string nameSuffix)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			BoneWeight[] boneWeights = sourceMesh.boneWeights;
			if (boneWeights == null || boneWeights.Length == 0)
			{
				return null;
			}
			HashSet<int> headBoneIndices = GetHeadBoneIndices(skinned, headBone);
			HashSet<int> armBoneIndices = GetArmBoneIndices(skinned, leftArm, rightArm);
			if (headBoneIndices.Count == 0 && armBoneIndices.Count == 0)
			{
				return null;
			}
			bool[] array = BuildPipeMask(sourceMesh, skinned, headBone);
			int num = boneWeights.Length;
			float[] array2 = new float[num];
			bool[] array3 = new bool[num];
			bool[] array4 = new bool[num];
			for (int i = 0; i < num; i++)
			{
				BoneWeight bw = boneWeights[i];
				array2[i] = InfluenceOf(bw, headBoneIndices);
				array3[i] = IsDominatedBy(bw, headBoneIndices) || (array != null && array[i]);
				array4[i] = IsDominatedBy(bw, armBoneIndices);
			}
			List<int> list = CollectSeamVertices(sourceMesh, array2, array3, array4);
			if (list.Count == 0)
			{
				return null;
			}
			Vector3[] vertices = sourceMesh.vertices;
			Vector3[] array5 = (Vector3[])vertices.Clone();
			BoneWeight[] array6 = (BoneWeight[])boneWeights.Clone();
			for (int j = 0; j < num; j++)
			{
				if (array4[j])
				{
					int num2 = NearestVertex(vertices[j], list, vertices);
					array5[j] = vertices[num2];
					array6[j] = boneWeights[num2];
				}
			}
			Mesh val = Object.Instantiate<Mesh>(sourceMesh);
			((Object)val).name = ((Object)sourceMesh).name + nameSuffix;
			val.vertices = array5;
			val.boneWeights = array6;
			for (int k = 0; k < val.subMeshCount; k++)
			{
				int[] triangles = sourceMesh.GetTriangles(k);
				List<int> list2 = new List<int>(triangles.Length);
				for (int l = 0; l < triangles.Length; l += 3)
				{
					int num3 = triangles[l];
					int num4 = triangles[l + 1];
					int num5 = triangles[l + 2];
					if (!ShouldCullTriangle(num3, num4, num5, array2, array3) && (!array4[num3] || !array4[num4] || !array4[num5]))
					{
						list2.Add(num3);
						list2.Add(num4);
						list2.Add(num5);
					}
				}
				val.SetTriangles(list2, k);
			}
			val.RecalculateBounds();
			return val;
		}

		private static List<int> CollectSeamVertices(Mesh mesh, float[] headInfluence, bool[] headDominant, bool[] armDominant)
		{
			HashSet<int> hashSet = new HashSet<int>();
			for (int i = 0; i < mesh.subMeshCount; i++)
			{
				int[] triangles = mesh.GetTriangles(i);
				for (int j = 0; j < triangles.Length; j += 3)
				{
					int num = triangles[j];
					int num2 = triangles[j + 1];
					int num3 = triangles[j + 2];
					if (!ShouldCullTriangle(num, num2, num3, headInfluence, headDominant) && (armDominant[num] || armDominant[num2] || armDominant[num3]))
					{
						if (!armDominant[num])
						{
							hashSet.Add(num);
						}
						if (!armDominant[num2])
						{
							hashSet.Add(num2);
						}
						if (!armDominant[num3])
						{
							hashSet.Add(num3);
						}
					}
				}
			}
			return new List<int>(hashSet);
		}

		private static int NearestVertex(Vector3 point, List<int> candidates, Vector3[] vertices)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			int result = candidates[0];
			float num = float.MaxValue;
			foreach (int candidate in candidates)
			{
				Vector3 val = vertices[candidate] - point;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude < num)
				{
					num = sqrMagnitude;
					result = candidate;
				}
			}
			return result;
		}

		private static Mesh? TryBuildFilteredMesh(Mesh sourceMesh, HashSet<int> removalBoneIndices, bool[]? pipeMask, string nameSuffix)
		{
			try
			{
				return BuildMeshWithoutBones(sourceMesh, removalBoneIndices, pipeMask, nameSuffix);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to build '" + ((Object)sourceMesh).name + nameSuffix + "'. " + ex.Message));
				return null;
			}
		}

		private static Mesh? BuildMeshWithoutBones(Mesh sourceMesh, HashSet<int> removalBoneIndices, bool[]? pipeMask, string nameSuffix)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			BoneWeight[] boneWeights = sourceMesh.boneWeights;
			if (boneWeights == null || boneWeights.Length == 0)
			{
				return null;
			}
			if (removalBoneIndices.Count == 0)
			{
				return null;
			}
			float[] array = new float[boneWeights.Length];
			bool[] array2 = new bool[boneWeights.Length];
			for (int i = 0; i < boneWeights.Length; i++)
			{
				BoneWeight bw = boneWeights[i];
				array[i] = InfluenceOf(bw, removalBoneIndices);
				array2[i] = IsDominatedBy(bw, removalBoneIndices) || (pipeMask != null && pipeMask[i]);
			}
			Mesh val = Object.Instantiate<Mesh>(sourceMesh);
			((Object)val).name = ((Object)sourceMesh).name + nameSuffix;
			for (int j = 0; j < val.subMeshCount; j++)
			{
				int[] triangles = sourceMesh.GetTriangles(j);
				List<int> list = new List<int>(triangles.Length);
				for (int k = 0; k < triangles.Length; k += 3)
				{
					int num = triangles[k];
					int num2 = triangles[k + 1];
					int num3 = triangles[k + 2];
					if (!ShouldCullTriangle(num, num2, num3, array, array2))
					{
						list.Add(num);
						list.Add(num2);
						list.Add(num3);
					}
				}
				val.SetTriangles(list, j);
			}
			val.RecalculateBounds();
			return val;
		}

		private static float InfluenceOf(BoneWeight bw, HashSet<int> set)
		{
			float num = 0f;
			if (set.Contains(((BoneWeight)(ref bw)).boneIndex0))
			{
				num += ((BoneWeight)(ref bw)).weight0;
			}
			if (set.Contains(((BoneWeight)(ref bw)).boneIndex1))
			{
				num += ((BoneWeight)(ref bw)).weight1;
			}
			if (set.Contains(((BoneWeight)(ref bw)).boneIndex2))
			{
				num += ((BoneWeight)(ref bw)).weight2;
			}
			if (set.Contains(((BoneWeight)(ref bw)).boneIndex3))
			{
				num += ((BoneWeight)(ref bw)).weight3;
			}
			return num;
		}

		private static bool IsDominatedBy(BoneWeight bw, HashSet<int> set)
		{
			int item = ((BoneWeight)(ref bw)).boneIndex0;
			float num = ((BoneWeight)(ref bw)).weight0;
			if (((BoneWeight)(ref bw)).weight1 > num)
			{
				num = ((BoneWeight)(ref bw)).weight1;
				item = ((BoneWeight)(ref bw)).boneIndex1;
			}
			if (((BoneWeight)(ref bw)).weight2 > num)
			{
				num = ((BoneWeight)(ref bw)).weight2;
				item = ((BoneWeight)(ref bw)).boneIndex2;
			}
			if (((BoneWeight)(ref bw)).weight3 > num)
			{
				num = ((BoneWeight)(ref bw)).weight3;
				item = ((BoneWeight)(ref bw)).boneIndex3;
			}
			if (num > 0f)
			{
				return set.Contains(item);
			}
			return false;
		}

		private static HashSet<int> GetHeadBoneIndices(SkinnedMeshRenderer skinned, Transform headBone)
		{
			HashSet<int> hashSet = new HashSet<int>();
			Transform[] bones = skinned.bones;
			for (int i = 0; i < bones.Length; i++)
			{
				Transform val = bones[i];
				if (!((Object)(object)val == (Object)null) && ((Object)(object)val == (Object)(object)headBone || val.IsChildOf(headBone) || ContainsHeadHint(((Object)val).name)))
				{
					hashSet.Add(i);
				}
			}
			return hashSet;
		}

		private static HashSet<int> GetArmBoneIndices(SkinnedMeshRenderer skinned, Transform? leftArm, Transform? rightArm)
		{
			HashSet<int> hashSet = new HashSet<int>();
			Transform[] bones = skinned.bones;
			for (int i = 0; i < bones.Length; i++)
			{
				Transform val = bones[i];
				if (!((Object)(object)val == (Object)null))
				{
					bool flag = (Object)(object)leftArm != (Object)null && ((Object)(object)val == (Object)(object)leftArm || val.IsChildOf(leftArm));
					bool flag2 = (Object)(object)rightArm != (Object)null && ((Object)(object)val == (Object)(object)rightArm || val.IsChildOf(rightArm));
					if (flag || flag2)
					{
						hashSet.Add(i);
					}
				}
			}
			return hashSet;
		}

		private static bool ShouldCullTriangle(int a, int b, int c, float[] headInfluence, bool[] dominantHead)
		{
			float num = ((a >= 0 && a < headInfluence.Length) ? headInfluence[a] : 0f);
			float num2 = ((b >= 0 && b < headInfluence.Length) ? headInfluence[b] : 0f);
			float num3 = ((c >= 0 && c < headInfluence.Length) ? headInfluence[c] : 0f);
			int num4 = 0;
			if (num >= 0.35f)
			{
				num4++;
			}
			if (num2 >= 0.35f)
			{
				num4++;
			}
			if (num3 >= 0.35f)
			{
				num4++;
			}
			int num5 = 0;
			if (a >= 0 && a < dominantHead.Length && dominantHead[a])
			{
				num5++;
			}
			if (b >= 0 && b < dominantHead.Length && dominantHead[b])
			{
				num5++;
			}
			if (c >= 0 && c < dominantHead.Length && dominantHead[c])
			{
				num5++;
			}
			if (num5 >= 2 || num4 >= 2)
			{
				return true;
			}
			float num6 = (num + num2 + num3) / 3f;
			if (num5 >= 1)
			{
				return num6 >= 0.3f;
			}
			return false;
		}

		private static bool ContainsHeadHint(string? value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return false;
			}
			string[] headBoneNameHints = Constants.HeadBoneNameHints;
			foreach (string value2 in headBoneNameHints)
			{
				if (value.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private static Mesh? ResolveReadable(Mesh sourceMesh, int meshId)
		{
			if (sourceMesh.isReadable)
			{
				return sourceMesh;
			}
			if (ReadableCopies.TryGetValue(meshId, out Mesh value))
			{
				return value;
			}
			Mesh val = null;
			try
			{
				Mesh val2 = MakeReadableMeshCopy(sourceMesh);
				if (val2.boneWeights.Length != 0 && val2.bindposes.Length != 0)
				{
					val = val2;
				}
				else
				{
					Object.Destroy((Object)(object)val2);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Mesh '" + ((Object)sourceMesh).name + "' could not be copied from the GPU. " + ex.Message));
			}
			if ((Object)(object)val == (Object)null && LoggedUnreadableMeshes.Add(meshId))
			{
				Plugin.Log.LogWarning((object)("Mesh '" + ((Object)sourceMesh).name + "' is not readable; the head can't be hidden on this model."));
			}
			ReadableCopies[meshId] = val;
			return val;
		}

		private static Mesh MakeReadableMeshCopy(Mesh nonReadableMesh)
		{
			//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)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			Mesh val = new Mesh
			{
				name = ((Object)nonReadableMesh).name,
				indexFormat = nonReadableMesh.indexFormat
			};
			nonReadableMesh.vertexBufferTarget = (Target)1;
			if (nonReadableMesh.vertexBufferCount > 0)
			{
				GraphicsBuffer vertexBuffer = nonReadableMesh.GetVertexBuffer(0);
				try
				{
					int num = vertexBuffer.stride * vertexBuffer.count;
					byte[] array = new byte[num];
					vertexBuffer.GetData((Array)array);
					val.SetVertexBufferParams(nonReadableMesh.vertexCount, nonReadableMesh.GetVertexAttributes());
					val.SetVertexBufferData<byte>(array, 0, 0, num, 0, (MeshUpdateFlags)0);
				}
				finally
				{
					((IDisposable)vertexBuffer)?.Dispose();
				}
			}
			nonReadableMesh.indexBufferTarget = (Target)2;
			val.subMeshCount = nonReadableMesh.subMeshCount;
			GraphicsBuffer indexBuffer = nonReadableMesh.GetIndexBuffer();
			try
			{
				int num2 = indexBuffer.stride * indexBuffer.count;
				byte[] array2 = new byte[num2];
				indexBuffer.GetData((Array)array2);
				val.SetIndexBufferParams(indexBuffer.count, nonReadableMesh.indexFormat);
				val.SetIndexBufferData<byte>(array2, 0, 0, num2, (MeshUpdateFlags)0);
			}
			finally
			{
				((IDisposable)indexBuffer)?.Dispose();
			}
			int num3 = 0;
			for (int i = 0; i < val.subMeshCount; i++)
			{
				int indexCount = (int)nonReadableMesh.GetIndexCount(i);
				val.SetSubMesh(i, new SubMeshDescriptor(num3, indexCount, (MeshTopology)0), (MeshUpdateFlags)0);
				num3 += indexCount;
			}
			val.bindposes = nonReadableMesh.bindposes;
			val.RecalculateBounds();
			return val;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "com.seeya.firstpersonview";

		public const string PLUGIN_NAME = "First-Person View";

		public const string PLUGIN_VERSION = "1.0.1";
	}
}
namespace FirstPersonView.Patches
{
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal static class LocalBodyViewPatches
	{
		private static readonly HashSet<string> _loggedTickErrors = new HashSet<string>();

		[HarmonyPatch("ConnectClientToPlayerObject")]
		[HarmonyPostfix]
		private static void ConnectClientToPlayerObject_Postfix(PlayerControllerB __instance)
		{
			if ((Object)(object)StartOfRound.Instance?.localPlayerController == (Object)(object)__instance)
			{
				VehicleCompat.EnsurePatched();
				LocalBodyViewController.ResetAllStates();
			}
		}

		[HarmonyPatch("LateUpdate")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void LateUpdate_Postfix(PlayerControllerB __instance)
		{
			try
			{
				LocalBodyViewController.Tick(__instance);
			}
			catch (Exception ex)
			{
				if (_loggedTickErrors.Add($"{ex.GetType()}: {ex.Message}"))
				{
					Plugin.Log.LogError((object)$"Local body update failed.\n{ex}");
				}
			}
		}

		[HarmonyPatch("SetHoverTipAndCurrentInteractTrigger")]
		[HarmonyPrefix]
		private static void SetHoverTipAndCurrentInteractTrigger_Prefix(PlayerControllerB __instance)
		{
			LocalBodyViewController.AlignCameraForInteractionRay(__instance);
		}
	}
}
namespace FirstPersonView.Compat
{
	internal static class MoreCompanyCompat
	{
		private static bool _initialized;

		private static bool _isInstalled;

		private static Type? _cosmeticApplicationType;

		private static Type? _cosmeticInstanceType;

		private static FieldInfo? _spawnedCosmeticsField;

		private static FieldInfo? _cosmeticTypeField;

		public static void Initialize()
		{
			if (!_initialized)
			{
				_initialized = true;
				_isInstalled = Chainloader.PluginInfos.ContainsKey("me.swipez.melonloader.morecompany");
				if (_isInstalled)
				{
					Plugin.Log.LogInfo((object)"MoreCompany detected.");
				}
			}
		}

		public static void ApplyLocalCosmeticVisibility(PlayerControllerB player, bool localBodyVisible, bool firstPersonArmsActive)
		{
			if (!_isInstalled || !ConfigManager.EnableMoreCompanyCompatibility.Value || !localBodyVisible || !TryResolveSpawnedCosmetics(player, out IEnumerable cosmetics))
			{
				return;
			}
			foreach (object item in cosmetics)
			{
				Component val = (Component)((item is Component) ? item : null);
				if (val != null)
				{
					bool flag = ShouldShowCosmetic(item, firstPersonArmsActive);
					if (val.gameObject.activeSelf != flag)
					{
						val.gameObject.SetActive(flag);
					}
				}
			}
		}

		private static bool TryResolveSpawnedCosmetics(PlayerControllerB player, out IEnumerable cosmetics)
		{
			cosmetics = Array.Empty<object>();
			if (!TryResolveTypes())
			{
				return false;
			}
			if (_cosmeticApplicationType == null || _spawnedCosmeticsField == null)
			{
				return false;
			}
			Transform obj = ((Component)player).transform.Find("ScavengerModel");
			Transform val = ((obj != null) ? obj.Find("metarig") : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Component component = ((Component)val).GetComponent(_cosmeticApplicationType);
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			object value = _spawnedCosmeticsField.GetValue(component);
			if (!(value is IEnumerable enumerable))
			{
				return false;
			}
			cosmetics = enumerable;
			return true;
		}

		private static bool ShouldShowCosmetic(object cosmetic, bool firstPersonArmsActive)
		{
			if (_cosmeticTypeField == null)
			{
				return true;
			}
			string text = _cosmeticTypeField.GetValue(cosmetic)?.ToString() ?? string.Empty;
			if (firstPersonArmsActive && text.IndexOf("ARM", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			return text switch
			{
				"HAT" => ConfigManager.ShowMoreCompanyHat.Value, 
				"CHEST" => ConfigManager.ShowMoreCompanyChest.Value, 
				"HIP" => ConfigManager.ShowMoreCompanyHip.Value, 
				"R_LOWER_ARM" => ConfigManager.ShowMoreCompanyRightLowerArm.Value, 
				"L_SHIN" => ConfigManager.ShowMoreCompanyLeftShin.Value, 
				"R_SHIN" => ConfigManager.ShowMoreCompanyRightShin.Value, 
				_ => true, 
			};
		}

		private static bool TryResolveTypes()
		{
			if (_cosmeticApplicationType != null && _spawnedCosmeticsField != null && _cosmeticInstanceType != null)
			{
				return true;
			}
			Assembly assembly = Reflection.FindAssembly("MoreCompany");
			if (assembly == null)
			{
				return false;
			}
			_cosmeticApplicationType = assembly.GetType("MoreCompany.Cosmetics.CosmeticApplication");
			_cosmeticInstanceType = assembly.GetType("MoreCompany.Cosmetics.CosmeticInstance");
			if (_cosmeticApplicationType == null || _cosmeticInstanceType == null)
			{
				return false;
			}
			_spawnedCosmeticsField = _cosmeticApplicationType.GetField("spawnedCosmetics", BindingFlags.Instance | BindingFlags.Public);
			_cosmeticTypeField = _cosmeticInstanceType.GetField("cosmeticType", BindingFlags.Instance | BindingFlags.P