Decompiled source of FreeCameraAndWaterCollision v1.3.2

BepInEx/plugins/FreeCameraAndCollision/FreeCameraAndCollision.dll

Decompiled 9 minutes ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Crest;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("FreeCameraAndCollision")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.1.0")]
[assembly: AssemblyInformationalVersion("1.3.1")]
[assembly: AssemblyProduct("FreeCameraAndCollision")]
[assembly: AssemblyTitle("FreeCameraAndCollision")]
[assembly: AssemblyVersion("1.3.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 FreeCameraAndCollision
{
	[HarmonyPatch(typeof(BoatCamera), "Start")]
	internal static class BoatCameraStartPatch
	{
		[HarmonyPostfix]
		private static void Postfix(BoatCamera __instance)
		{
			FreeCameraAndCollisionPlugin.Instance?.AttachController(__instance);
		}
	}
	[HarmonyPatch(typeof(BoatCamera), "SwitchOff")]
	internal static class BoatCameraSwitchOffPatch
	{
		[HarmonyPrefix]
		private static void Prefix(BoatCamera __instance)
		{
			FreeCameraController.ExitIfOwnedBy(__instance);
		}
	}
	internal sealed class CameraConstraintResolver
	{
		private readonly FreeCameraAndCollisionPlugin plugin;

		private readonly Object queryContext;

		private readonly SampleHeightHelper waterHeightSampler = new SampleHeightHelper();

		internal CameraConstraintResolver(FreeCameraAndCollisionPlugin ownerPlugin, Object owner)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			plugin = ownerPlugin;
			queryContext = owner;
		}

		internal Vector3 ConstrainFreeCameraPosition(Vector3 position, Vector3 focus, float maximumDistance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_001b: 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_0032: 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_0062: 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_0043: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			position = ClampToMaximumDistance(position, focus, maximumDistance);
			position = ApplyWaterCollision(position);
			Vector3 val = position - focus;
			float num = maximumDistance * maximumDistance;
			if (((Vector3)(ref val)).sqrMagnitude <= num)
			{
				return position;
			}
			float num2 = position.y - focus.y;
			if (Mathf.Abs(num2) >= maximumDistance)
			{
				return focus + Vector3.up * Mathf.Sign(num2) * maximumDistance;
			}
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(val.x, 0f, val.z);
			float num3 = Mathf.Sqrt(num - num2 * num2);
			if (((Vector3)(ref val2)).sqrMagnitude > num3 * num3)
			{
				val2 = ((Vector3)(ref val2)).normalized * num3;
			}
			return focus + val2 + Vector3.up * num2;
		}

		private Vector3 ClampToMaximumDistance(Vector3 position, Vector3 focus, float maximumDistance)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = position - focus;
			if (((Vector3)(ref val)).sqrMagnitude <= maximumDistance * maximumDistance)
			{
				return position;
			}
			return focus + ((Vector3)(ref val)).normalized * maximumDistance;
		}

		internal Vector3 ApplyWaterCollision(Vector3 position)
		{
			//IL_001f: 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_007f: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			if (!plugin.WaterCollision.Value || (Object)(object)OceanRenderer.Instance == (Object)null)
			{
				return position;
			}
			waterHeightSampler.Init(position, plugin.SphereRadius.Value * 2f, true, queryContext);
			float num = default(float);
			if (!waterHeightSampler.Sample(ref num))
			{
				return position;
			}
			float num2 = num + plugin.SphereRadius.Value + plugin.SurfacePadding.Value;
			if (position.y < num2)
			{
				position.y = num2;
			}
			return position;
		}
	}
	internal static class CameraDistanceLimits
	{
		internal const float FreeCameraMaximumDistanceFromBoat = 320f;
	}
	internal sealed class DroneVelocityState
	{
		private const float VelocityTransitionTime = 2f;

		private const float SpeedMultiplierTransitionTime = 1f;

		private const float OppositeInputDecelerationTime = 1f;

		private const float MovementInputEpsilonSquared = 0.0001f;

		private const float CollisionCorrectionEpsilonSquared = 1E-06f;

		private float currentSpeedMultiplier = 1f;

		private float speedMultiplierTransitionStart = 1f;

		private float speedMultiplierTransitionTarget = 1f;

		private float speedMultiplierTransitionElapsed;

		private bool movementInputWasActive;

		private float stoppingVelocityChangeRate;

		internal Vector3 LocalVelocity { get; private set; }

		internal void Reset(float initialSpeedMultiplier)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			LocalVelocity = Vector3.zero;
			currentSpeedMultiplier = initialSpeedMultiplier;
			speedMultiplierTransitionStart = initialSpeedMultiplier;
			speedMultiplierTransitionTarget = initialSpeedMultiplier;
			speedMultiplierTransitionElapsed = 1f;
			movementInputWasActive = false;
			stoppingVelocityChangeRate = 0f;
		}

		internal Vector3 Update(Vector3 localInput, float baseSpeed, float requestedSpeedMultiplier, float deltaTime)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_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_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_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_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			bool flag = UpdateSpeedMultiplier(requestedSpeedMultiplier, deltaTime);
			if (((Vector3)(ref localInput)).sqrMagnitude > 1f)
			{
				((Vector3)(ref localInput)).Normalize();
			}
			bool flag2 = ((Vector3)(ref localInput)).sqrMagnitude >= 0.0001f;
			if (!flag2)
			{
				localInput = Vector3.zero;
				if (movementInputWasActive)
				{
					Vector3 localVelocity = LocalVelocity;
					stoppingVelocityChangeRate = ((Vector3)(ref localVelocity)).magnitude / 2f;
				}
			}
			Vector3 val = localInput * baseSpeed * currentSpeedMultiplier;
			if (flag2)
			{
				float num = Mathf.Max(currentSpeedMultiplier, requestedSpeedMultiplier);
				if (Vector3.Dot(LocalVelocity, val) < 0f)
				{
					float num2 = baseSpeed * num / 1f;
					LocalVelocity = Vector3.MoveTowards(LocalVelocity, Vector3.zero, num2 * deltaTime);
				}
				else
				{
					float num3 = baseSpeed * num / 2f;
					if (flag)
					{
						float num4 = baseSpeed * Mathf.Abs(speedMultiplierTransitionTarget - speedMultiplierTransitionStart) / 1f;
						num3 = Mathf.Max(num3, num4);
					}
					LocalVelocity = Vector3.MoveTowards(LocalVelocity, val, num3 * deltaTime);
				}
			}
			else
			{
				LocalVelocity = Vector3.MoveTowards(LocalVelocity, val, stoppingVelocityChangeRate * deltaTime);
			}
			movementInputWasActive = flag2;
			return LocalVelocity;
		}

		internal void RemoveBlockedComponent(Quaternion cameraRotation, Vector3 constraintCorrection)
		{
			//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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_0042: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			if (!(((Vector3)(ref constraintCorrection)).sqrMagnitude < 1E-06f))
			{
				Vector3 normalized = ((Vector3)(ref constraintCorrection)).normalized;
				Vector3 val = cameraRotation * LocalVelocity;
				float num = Vector3.Dot(val, normalized);
				if (!(num >= 0f))
				{
					val -= normalized * num;
					LocalVelocity = Quaternion.Inverse(cameraRotation) * val;
				}
			}
		}

		private bool UpdateSpeedMultiplier(float requestedSpeedMultiplier, float deltaTime)
		{
			if (!Mathf.Approximately(requestedSpeedMultiplier, speedMultiplierTransitionTarget))
			{
				speedMultiplierTransitionStart = currentSpeedMultiplier;
				speedMultiplierTransitionTarget = requestedSpeedMultiplier;
				speedMultiplierTransitionElapsed = 0f;
			}
			if (speedMultiplierTransitionElapsed >= 1f)
			{
				currentSpeedMultiplier = speedMultiplierTransitionTarget;
				return false;
			}
			speedMultiplierTransitionElapsed = Mathf.Min(speedMultiplierTransitionElapsed + deltaTime, 1f);
			currentSpeedMultiplier = Mathf.Lerp(speedMultiplierTransitionStart, speedMultiplierTransitionTarget, speedMultiplierTransitionElapsed / 1f);
			return true;
		}
	}
	[DefaultExecutionOrder(10000)]
	internal sealed class FreeCameraController : MonoBehaviour
	{
		private const KeyCode ToggleKey = (KeyCode)98;

		private const KeyCode FollowShipToggleKey = (KeyCode)104;

		private const KeyCode ControllerToggleKey = (KeyCode)338;

		private const KeyCode ControllerDescendKey = (KeyCode)334;

		private const KeyCode ControllerRiseKey = (KeyCode)335;

		private const float SpeedBoostMultiplier = 2f;

		private const float PrecisionSpeedMultiplier = 0.5f;

		private const float MinimumZoom = 20f;

		private const float MouseZoomSpeed = 30f;

		private const float ControllerZoomSpeed = 35f;

		private const float ZoomResponseSpeed = 100f;

		private const float WorldShiftDistanceThreshold = 20f;

		private const string PrimaryHorizontalAxis = "Oculus_CrossPlatform_PrimaryThumbstickHorizontal";

		private const string PrimaryVerticalAxis = "Oculus_CrossPlatform_PrimaryThumbstickVertical";

		private const string SecondaryHorizontalAxis = "Oculus_CrossPlatform_SecondaryThumbstickHorizontal";

		private const string SecondaryVerticalAxis = "Oculus_CrossPlatform_SecondaryThumbstickVertical";

		private const string PrimaryTriggerAxis = "Oculus_CrossPlatform_PrimaryIndexTrigger";

		private const string SecondaryTriggerAxis = "Oculus_CrossPlatform_SecondaryIndexTrigger";

		private const string MouseHorizontalAxis = "Mouse X";

		private const string MouseVerticalAxis = "Mouse Y";

		private const string MouseScrollAxis = "Mouse ScrollWheel";

		private static readonly FieldInfo CenterEyeField = AccessTools.Field(typeof(BoatCamera), "centerEye");

		private static readonly FieldInfo PlayerLooksField = AccessTools.Field(typeof(BoatCamera), "playerLooks");

		private static readonly FieldInfo BoatLooksField = AccessTools.Field(typeof(BoatCamera), "boatLooks");

		private BoatCamera boatCamera;

		private FreeCameraAndCollisionPlugin plugin;

		private CameraConstraintResolver constraintResolver;

		private Transform centerEye;

		private Camera unityCamera;

		private MouseLook[] playerLooks;

		private MouseLook[] boatLooks;

		private bool[] savedBoatLookStates;

		private readonly FreeCameraRotationState rotationState = new FreeCameraRotationState();

		private readonly DroneVelocityState droneVelocityState = new DroneVelocityState();

		private bool initialized;

		private bool freeCameraActive;

		private Transform followedBoat;

		private bool followShipTranslation;

		private Vector3 lastBoatPosition;

		private Vector3 freeCameraPosition;

		private float lookSensitivityX = 2f;

		private float lookSensitivityY = 2f;

		private float minimumLookY = -80f;

		private float maximumLookY = 80f;

		private Vector3 savedCenterEyeLocalPosition;

		private Quaternion savedCenterEyeLocalRotation;

		private float savedFieldOfView;

		private float targetFieldOfView;

		private OVRPlayerController playerController;

		private bool savedPlayerControllerEnabled;

		internal static FreeCameraController ActiveController { get; private set; }

		internal static bool IsInputCaptured
		{
			get
			{
				if ((Object)(object)ActiveController != (Object)null)
				{
					return ActiveController.freeCameraActive;
				}
				return false;
			}
		}

		internal void Initialize(BoatCamera owner, FreeCameraAndCollisionPlugin ownerPlugin)
		{
			if (initialized && (Object)(object)boatCamera == (Object)(object)owner && (Object)(object)plugin == (Object)(object)ownerPlugin)
			{
				return;
			}
			boatCamera = owner;
			plugin = ownerPlugin;
			ref Transform reference = ref centerEye;
			object? obj = CenterEyeField?.GetValue(owner);
			reference = (Transform)((obj is Transform) ? obj : null);
			playerLooks = PlayerLooksField?.GetValue(owner) as MouseLook[];
			boatLooks = BoatLooksField?.GetValue(owner) as MouseLook[];
			if ((Object)(object)centerEye == (Object)null)
			{
				ownerPlugin.LogInitializationError("Free camera could not initialize: BoatCamera.centerEye was not found.");
				((Behaviour)this).enabled = false;
				return;
			}
			unityCamera = ((Component)centerEye).GetComponent<Camera>();
			if ((Object)(object)unityCamera == (Object)null)
			{
				unityCamera = ((Component)centerEye).GetComponentInChildren<Camera>();
			}
			if ((Object)(object)unityCamera == (Object)null)
			{
				unityCamera = Camera.main;
			}
			constraintResolver = new CameraConstraintResolver(ownerPlugin, (Object)(object)this);
			CacheVanillaFirstPersonLookSettings();
			initialized = true;
		}

		internal static void ExitActiveCamera()
		{
			ActiveController?.ExitFreeCamera();
		}

		internal static void ExitIfOwnedBy(BoatCamera owner)
		{
			if ((Object)(object)ActiveController != (Object)null && (Object)(object)ActiveController.boatCamera == (Object)(object)owner)
			{
				ActiveController.ExitFreeCamera();
			}
		}

		private void Update()
		{
			if (!initialized)
			{
				return;
			}
			bool flag = Input.GetKeyDown((KeyCode)98) || (GameInput.controllerEnabled && Input.GetKeyDown((KeyCode)338));
			if (!freeCameraActive)
			{
				if (flag && CanEnterFreeCamera())
				{
					EnterFreeCamera();
				}
			}
			else if (flag || !CanRemainActive())
			{
				ExitFreeCamera();
			}
			else
			{
				UpdateFreeCameraInput();
			}
		}

		private void LateUpdate()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (initialized && BoatCamera.on && !((Object)(object)GameState.currentBoat == (Object)null))
			{
				if (freeCameraActive)
				{
					centerEye.position = freeCameraPosition;
					centerEye.rotation = rotationState.Rotation;
				}
				else
				{
					ApplyThirdPersonWaterConstraint();
				}
			}
		}

		private void OnDisable()
		{
			if (freeCameraActive)
			{
				ExitFreeCamera();
			}
		}

		private void OnDestroy()
		{
			if (freeCameraActive)
			{
				ExitFreeCamera();
			}
		}

		private bool CanEnterFreeCamera()
		{
			return IsFreeCameraContextAvailable();
		}

		private bool CanRemainActive()
		{
			if (IsFreeCameraContextAvailable() && (Object)(object)followedBoat != (Object)null)
			{
				return (Object)(object)GameState.currentBoat == (Object)(object)followedBoat;
			}
			return false;
		}

		private static bool IsFreeCameraContextAvailable()
		{
			if (BoatCamera.on && GameState.playing && !GameState.currentlyLoading && (Object)(object)GameState.currentBoat != (Object)null && (Object)(object)GameState.currentShipyard == (Object)null && !GameState.inCursorMenu)
			{
				return !GameState.VREnabled;
			}
			return false;
		}

		private void EnterFreeCamera()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ActiveController != (Object)null && (Object)(object)ActiveController != (Object)(object)this)
			{
				ActiveController.ExitFreeCamera();
			}
			followedBoat = GameState.currentBoat;
			followShipTranslation = true;
			lastBoatPosition = followedBoat.position;
			freeCameraPosition = centerEye.position;
			rotationState.Initialize(centerEye.rotation, plugin.MovementMode.Value, minimumLookY, maximumLookY);
			droneVelocityState.Reset(GetMovementSpeedMultiplier());
			savedCenterEyeLocalPosition = centerEye.localPosition;
			savedCenterEyeLocalRotation = centerEye.localRotation;
			if ((Object)(object)unityCamera != (Object)null)
			{
				savedFieldOfView = unityCamera.fieldOfView;
				targetFieldOfView = savedFieldOfView;
			}
			SaveAndDisableBoatLook();
			SaveAndDisablePlayerMovement();
			ActiveController = this;
			freeCameraActive = true;
		}

		private void ExitFreeCamera()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (freeCameraActive)
			{
				freeCameraActive = false;
				if ((Object)(object)centerEye != (Object)null)
				{
					centerEye.localPosition = savedCenterEyeLocalPosition;
					centerEye.localRotation = savedCenterEyeLocalRotation;
				}
				if ((Object)(object)unityCamera != (Object)null)
				{
					unityCamera.fieldOfView = savedFieldOfView;
				}
				RestoreBoatLook();
				RestorePlayerMovement();
				followedBoat = null;
				droneVelocityState.Reset(1f);
				if ((Object)(object)ActiveController == (Object)(object)this)
				{
					ActiveController = null;
				}
			}
		}

		private void UpdateFreeCameraInput()
		{
			float deltaTime = Mathf.Min(Time.unscaledDeltaTime, 0.05f);
			if (Input.GetKeyDown((KeyCode)104))
			{
				followShipTranslation = !followShipTranslation;
			}
			if (rotationState.SetMode(plugin.MovementMode.Value))
			{
				droneVelocityState.Reset(GetMovementSpeedMultiplier());
			}
			UpdateFreeCameraLook(deltaTime);
			UpdateFreeCameraMovement(deltaTime);
			UpdateFreeCameraZoom(deltaTime);
		}

		private void UpdateFreeCameraLook(float deltaTime)
		{
			float num = 0f;
			float num2 = 0f;
			if (GameInput.controllerEnabled)
			{
				num = Input.GetAxis("Oculus_CrossPlatform_SecondaryThumbstickHorizontal");
				num2 = Input.GetAxis("Oculus_CrossPlatform_SecondaryThumbstickVertical");
			}
			float axis = Input.GetAxis("Mouse X");
			float axis2 = Input.GetAxis("Mouse Y");
			if (num != 0f || num2 != 0f)
			{
				GameState.lookingWithController = true;
			}
			if (axis != 0f || axis2 != 0f)
			{
				GameState.lookingWithController = false;
			}
			float num3 = (float)Settings.mouseSens / 5f + 0.1f;
			float yawDelta = (num + axis) * lookSensitivityX * num3;
			float keyboardAxis = GetKeyboardAxis((KeyCode)113, (KeyCode)101);
			rotationState.UpdateLook(yawDelta, axis2 * lookSensitivityY * num3, num2 * lookSensitivityY * num3, plugin.InvertDroneMousePitch.Value, keyboardAxis, plugin.CameraRollingSpeed.Value, Input.GetKeyDown((KeyCode)114), deltaTime);
		}

		private void UpdateFreeCameraMovement(float deltaTime)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: 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_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: 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_01c0: 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_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: 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_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = followedBoat.position;
			Vector3 val = position - lastBoatPosition;
			lastBoatPosition = position;
			if (((Vector3)(ref val)).sqrMagnitude > 400f)
			{
				freeCameraPosition += val;
				val = Vector3.zero;
			}
			else if (!followShipTranslation)
			{
				val = Vector3.zero;
			}
			float num = GetKeyboardAxis((KeyCode)119, (KeyCode)115);
			float num2 = GetKeyboardAxis((KeyCode)100, (KeyCode)97);
			float num3 = GetKeyboardAxis((KeyCode)32, (KeyCode)306);
			if (Input.GetKey((KeyCode)305))
			{
				num3 -= 1f;
			}
			if (GameInput.controllerEnabled)
			{
				num += Input.GetAxis("Oculus_CrossPlatform_PrimaryThumbstickVertical");
				num2 += Input.GetAxis("Oculus_CrossPlatform_PrimaryThumbstickHorizontal");
				if (Input.GetKey((KeyCode)335))
				{
					num3 += 1f;
				}
				if (Input.GetKey((KeyCode)334))
				{
					num3 -= 1f;
				}
			}
			float movementSpeedMultiplier = GetMovementSpeedMultiplier();
			Vector3 val3;
			if (rotationState.Mode == FreeCameraMovementMode.Drone)
			{
				Vector3 localInput = default(Vector3);
				((Vector3)(ref localInput))..ctor(num2, num3, num);
				Vector3 val2 = droneVelocityState.Update(localInput, plugin.CameraSpeed.Value, movementSpeedMultiplier, deltaTime);
				val3 = rotationState.Rotation * val2 * deltaTime;
			}
			else
			{
				Quaternion movementRotation = rotationState.MovementRotation;
				Vector3 val4 = movementRotation * Vector3.forward * num + movementRotation * Vector3.right * num2 + Vector3.up * num3;
				if (((Vector3)(ref val4)).sqrMagnitude > 1f)
				{
					((Vector3)(ref val4)).Normalize();
				}
				val3 = val4 * (float)plugin.CameraSpeed.Value * movementSpeedMultiplier * deltaTime;
			}
			Vector3 focus = position;
			Vector3 val5 = freeCameraPosition + val + val3;
			Vector3 val6 = constraintResolver.ConstrainFreeCameraPosition(val5, focus, 320f);
			if (rotationState.Mode == FreeCameraMovementMode.Drone)
			{
				droneVelocityState.RemoveBlockedComponent(rotationState.Rotation, val6 - val5);
			}
			freeCameraPosition = val6;
		}

		private static float GetMovementSpeedMultiplier()
		{
			float num = 1f;
			if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303))
			{
				num *= 2f;
			}
			if (Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307))
			{
				num *= 0.5f;
			}
			return num;
		}

		private void UpdateFreeCameraZoom(float deltaTime)
		{
			if (!((Object)(object)unityCamera == (Object)null))
			{
				float axis = Input.GetAxis("Mouse ScrollWheel");
				float num = 0f;
				if (GameInput.controllerEnabled)
				{
					num = Input.GetAxis("Oculus_CrossPlatform_SecondaryIndexTrigger") - Input.GetAxis("Oculus_CrossPlatform_PrimaryIndexTrigger");
				}
				targetFieldOfView -= axis * 30f;
				targetFieldOfView -= num * 35f * deltaTime;
				targetFieldOfView = Mathf.Clamp(targetFieldOfView, 20f, savedFieldOfView);
				unityCamera.fieldOfView = Mathf.MoveTowards(unityCamera.fieldOfView, targetFieldOfView, 100f * deltaTime);
			}
		}

		private void ApplyThirdPersonWaterConstraint()
		{
			//IL_0012: 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)
			centerEye.position = constraintResolver.ApplyWaterCollision(centerEye.position);
		}

		private void CacheVanillaFirstPersonLookSettings()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_0029: 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_0043: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (playerLooks == null)
			{
				return;
			}
			for (int i = 0; i < playerLooks.Length; i++)
			{
				MouseLook val = playerLooks[i];
				if (!((Object)(object)val == (Object)null))
				{
					if ((int)val.axes == 1 || (int)val.axes == 0)
					{
						lookSensitivityX = val.sensitivityX;
					}
					if ((int)val.axes == 2 || (int)val.axes == 0)
					{
						lookSensitivityY = val.sensitivityY;
						minimumLookY = val.minimumY;
						maximumLookY = val.maximumY;
					}
				}
			}
		}

		private void SaveAndDisableBoatLook()
		{
			if (boatLooks == null)
			{
				savedBoatLookStates = null;
				return;
			}
			savedBoatLookStates = new bool[boatLooks.Length];
			for (int i = 0; i < boatLooks.Length; i++)
			{
				MouseLook val = boatLooks[i];
				if (!((Object)(object)val == (Object)null))
				{
					savedBoatLookStates[i] = ((Behaviour)val).enabled;
					((Behaviour)val).enabled = false;
				}
			}
		}

		private void RestoreBoatLook()
		{
			if (boatLooks == null || savedBoatLookStates == null)
			{
				return;
			}
			int num = Mathf.Min(boatLooks.Length, savedBoatLookStates.Length);
			for (int i = 0; i < num; i++)
			{
				if ((Object)(object)boatLooks[i] != (Object)null)
				{
					((Behaviour)boatLooks[i]).enabled = savedBoatLookStates[i];
				}
			}
			savedBoatLookStates = null;
		}

		private void SaveAndDisablePlayerMovement()
		{
			playerController = Refs.ovrController;
			if (!((Object)(object)playerController == (Object)null))
			{
				savedPlayerControllerEnabled = ((Behaviour)playerController).enabled;
				playerController.Stop();
				((Behaviour)playerController).enabled = false;
			}
		}

		private void RestorePlayerMovement()
		{
			if ((Object)(object)playerController != (Object)null)
			{
				((Behaviour)playerController).enabled = savedPlayerControllerEnabled;
			}
			playerController = null;
		}

		private static float GetKeyboardAxis(KeyCode positive, KeyCode negative)
		{
			//IL_0006: 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)
			float num = 0f;
			if (Input.GetKey(positive))
			{
				num += 1f;
			}
			if (Input.GetKey(negative))
			{
				num -= 1f;
			}
			return num;
		}
	}
	internal enum FreeCameraMovementMode
	{
		World,
		Drone
	}
	internal sealed class FreeCameraRotationState
	{
		private const float RollReferenceEpsilonSquared = 0.0001f;

		private const float RollResetSpeedDegreesPerSecond = 120f;

		private float minimumPitch;

		private float maximumPitch;

		private float worldYaw;

		private float worldPitch;

		private float worldRoll;

		private bool rollResetActive;

		internal Quaternion Rotation { get; private set; }

		internal FreeCameraMovementMode Mode { get; private set; }

		internal Quaternion MovementRotation
		{
			get
			{
				//IL_0022: 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)
				if (Mode != FreeCameraMovementMode.Drone)
				{
					return Quaternion.Euler(0f - worldPitch, worldYaw, 0f);
				}
				return Rotation;
			}
		}

		internal void Initialize(Quaternion initialRotation, FreeCameraMovementMode mode, float minimumWorldPitch, float maximumWorldPitch)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Rotation = initialRotation;
			Mode = mode;
			minimumPitch = minimumWorldPitch;
			maximumPitch = maximumWorldPitch;
			rollResetActive = false;
			UpdateWorldAnglesFromRotation();
		}

		internal bool SetMode(FreeCameraMovementMode mode)
		{
			if (mode == Mode)
			{
				return false;
			}
			Mode = mode;
			if (Mode == FreeCameraMovementMode.World)
			{
				UpdateWorldAnglesFromRotation();
			}
			return true;
		}

		internal void UpdateLook(float yawDelta, float mousePitchDelta, float controllerPitchDelta, bool invertDroneMousePitch, float rollInput, float rollingSpeed, bool resetRollPressed, float deltaTime)
		{
			float num = ((Mode == FreeCameraMovementMode.Drone && invertDroneMousePitch) ? (-1f) : 1f);
			float pitchDelta = controllerPitchDelta + mousePitchDelta * num;
			float rollDelta = rollInput * rollingSpeed * deltaTime;
			if (rollInput != 0f)
			{
				rollResetActive = false;
			}
			else if (resetRollPressed)
			{
				rollResetActive = true;
			}
			if (Mode == FreeCameraMovementMode.Drone)
			{
				UpdateDroneRotation(yawDelta, pitchDelta, rollDelta, deltaTime);
			}
			else
			{
				UpdateWorldRotation(yawDelta, pitchDelta, rollDelta, deltaTime);
			}
		}

		private void UpdateWorldRotation(float yawDelta, float pitchDelta, float rollDelta, float deltaTime)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			worldYaw = NormalizeAngle(worldYaw + yawDelta);
			worldPitch = Mathf.Clamp(worldPitch + pitchDelta, minimumPitch, maximumPitch);
			if (rollResetActive)
			{
				worldRoll = Mathf.MoveTowardsAngle(worldRoll, 0f, 120f * deltaTime);
				if (worldRoll == 0f)
				{
					rollResetActive = false;
				}
			}
			else
			{
				worldRoll = NormalizeAngle(worldRoll + rollDelta);
			}
			Rotation = Quaternion.Euler(0f - worldPitch, worldYaw, worldRoll);
		}

		private void UpdateDroneRotation(float yawDelta, float pitchDelta, float rollDelta, float deltaTime)
		{
			//IL_0004: 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_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_0017: 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)
			Quaternion val = Quaternion.Euler(0f - pitchDelta, yawDelta, rollDelta);
			Quaternion val2 = Rotation * val;
			Rotation = ((Quaternion)(ref val2)).normalized;
			if (rollResetActive)
			{
				UpdateDroneRollReset(deltaTime);
			}
		}

		private void UpdateWorldAnglesFromRotation()
		{
			//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_000e: 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_0021: 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)
			Quaternion rotation = Rotation;
			Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles;
			worldYaw = NormalizeAngle(eulerAngles.y);
			worldPitch = Mathf.Clamp(0f - NormalizeAngle(eulerAngles.x), minimumPitch, maximumPitch);
			worldRoll = NormalizeAngle(eulerAngles.z);
		}

		private void UpdateDroneRollReset(float deltaTime)
		{
			//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_000b: 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_0012: 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_0021: 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_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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_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)
			//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_009d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Rotation * Vector3.forward;
			Vector3 val2 = Rotation * Vector3.up;
			Vector3 val3 = Vector3.ProjectOnPlane(Vector3.up, val);
			if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
			{
				val3 = Vector3.ProjectOnPlane(Vector3.forward, val);
			}
			if (!(((Vector3)(ref val3)).sqrMagnitude < 0.0001f))
			{
				((Vector3)(ref val3)).Normalize();
				float num = Vector3.SignedAngle(val3, val2, val);
				float num2 = Mathf.MoveTowardsAngle(num, 0f, 120f * deltaTime);
				float num3 = Mathf.DeltaAngle(num, num2);
				Quaternion val4 = Rotation * Quaternion.AngleAxis(num3, Vector3.forward);
				Rotation = ((Quaternion)(ref val4)).normalized;
				if (num2 == 0f)
				{
					rollResetActive = false;
				}
			}
		}

		private static float NormalizeAngle(float angle)
		{
			while (angle > 180f)
			{
				angle -= 360f;
			}
			while (angle < -180f)
			{
				angle += 360f;
			}
			return angle;
		}
	}
	internal static class GameInputSuppression
	{
		internal static bool AllowOriginalOrNeutralize(ref bool result)
		{
			if (!FreeCameraController.IsInputCaptured)
			{
				return true;
			}
			result = false;
			return false;
		}

		internal static bool AllowOriginalOrNeutralize(ref float result)
		{
			if (!FreeCameraController.IsInputCaptured)
			{
				return true;
			}
			result = 0f;
			return false;
		}
	}
	[HarmonyPatch(typeof(GameInput), "GetKey")]
	internal static class GameInputGetKeyPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref bool __result)
		{
			return GameInputSuppression.AllowOriginalOrNeutralize(ref __result);
		}
	}
	[HarmonyPatch(typeof(GameInput), "GetKeyDown")]
	internal static class GameInputGetKeyDownPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref bool __result)
		{
			return GameInputSuppression.AllowOriginalOrNeutralize(ref __result);
		}
	}
	[HarmonyPatch(typeof(GameInput), "GetKeyUp")]
	internal static class GameInputGetKeyUpPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref bool __result)
		{
			return GameInputSuppression.AllowOriginalOrNeutralize(ref __result);
		}
	}
	[HarmonyPatch(typeof(GameInput), "GetScrollAxis")]
	internal static class GameInputGetScrollAxisPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref float __result)
		{
			return GameInputSuppression.AllowOriginalOrNeutralize(ref __result);
		}
	}
	[HarmonyPatch(typeof(GameInput), "GetPrimaryHorizontal")]
	internal static class GameInputGetPrimaryHorizontalPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref float __result)
		{
			return GameInputSuppression.AllowOriginalOrNeutralize(ref __result);
		}
	}
	[HarmonyPatch(typeof(GameInput), "GetPrimaryVertical")]
	internal static class GameInputGetPrimaryVerticalPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref float __result)
		{
			return GameInputSuppression.AllowOriginalOrNeutralize(ref __result);
		}
	}
	[HarmonyPatch(typeof(GameInput), "GetSecondaryHorizontal")]
	internal static class GameInputGetSecondaryHorizontalPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref float __result)
		{
			return GameInputSuppression.AllowOriginalOrNeutralize(ref __result);
		}
	}
	[HarmonyPatch(typeof(GameInput), "GetSecondaryVertical")]
	internal static class GameInputGetSecondaryVerticalPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref float __result)
		{
			return GameInputSuppression.AllowOriginalOrNeutralize(ref __result);
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public bool? Browsable;

		public bool? HideDefaultButton;

		public bool? ShowRangeAsPercent;

		public int? Order;

		public Action<ConfigEntryBase> CustomDrawer;
	}
	[BepInPlugin("com.DogEggz.sailwind.freecameraandcollision", "FreeCamera and Collision", "1.3.1")]
	public sealed class FreeCameraAndCollisionPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.DogEggz.sailwind.freecameraandcollision";

		public const string PluginName = "FreeCamera and Collision";

		public const string PluginVersion = "1.3.1";

		private static readonly GUIContent WorldMovementButton = new GUIContent("World", "Camera movement related to game world.");

		private static readonly GUIContent DroneMovementButton = new GUIContent("Drone", "Camera movement based on camera axis.");

		private static readonly GUIContent InvertPitchToggle = new GUIContent("Invert Mouse Pitch", "Invert vertical mouse input in Drone mode only.");

		private static readonly ConfigDefinition[] ObsoleteConfigDefinitions = (ConfigDefinition[])(object)new ConfigDefinition[3]
		{
			new ConfigDefinition("Collision", "Collision Enabled"),
			new ConfigDefinition("Collision", "Solid Collision"),
			new ConfigDefinition("Collision Tuning", "Return Smooth Time")
		};

		private static readonly PropertyInfo OrphanedEntriesProperty = AccessTools.Property(typeof(ConfigFile), "OrphanedEntries");

		private Harmony harmony;

		internal static FreeCameraAndCollisionPlugin Instance { get; private set; }

		internal ConfigEntry<bool> WaterCollision { get; private set; }

		internal ConfigEntry<float> SphereRadius { get; private set; }

		internal ConfigEntry<float> SurfacePadding { get; private set; }

		internal ConfigEntry<FreeCameraMovementMode> MovementMode { get; private set; }

		internal ConfigEntry<int> CameraSpeed { get; private set; }

		internal ConfigEntry<int> CameraRollingSpeed { get; private set; }

		internal ConfigEntry<bool> InvertDroneMousePitch { get; private set; }

		private void Awake()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			Instance = this;
			BindConfiguration();
			RemoveObsoleteConfiguration();
			harmony = new Harmony("com.DogEggz.sailwind.freecameraandcollision");
			harmony.PatchAll(Assembly.GetExecutingAssembly());
			if ((Object)(object)BoatCamera.instance != (Object)null)
			{
				AttachController(BoatCamera.instance);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"FreeCamera and Collision 1.3.1 loaded.");
		}

		private void OnDestroy()
		{
			FreeCameraController.ExitActiveCamera();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		internal void AttachController(BoatCamera boatCamera)
		{
			if (!((Object)(object)boatCamera == (Object)null))
			{
				(((Component)boatCamera).GetComponent<FreeCameraController>() ?? ((Component)boatCamera).gameObject.AddComponent<FreeCameraController>()).Initialize(boatCamera, this);
			}
		}

		internal void LogInitializationError(string message)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)message);
		}

		private void BindConfiguration()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			MovementMode = ((BaseUnityPlugin)this).Config.Bind<FreeCameraMovementMode>("Free Camera", "Movement Mode", FreeCameraMovementMode.World, new ConfigDescription("Select how free-camera movement is oriented.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 10,
					HideDefaultButton = true,
					CustomDrawer = DrawMovementModeButtons
				}
			}));
			CameraSpeed = BindIntegerSlider("Free Camera", "Camera Speed", 10, 1, 40, "Free-camera positional movement speed. Shift doubles it and Alt halves it. Drone acceleration and stopping use a two-second response; Shift/Alt speed changes use one second.", 20, showDefaultButton: true);
			CameraRollingSpeed = BindIntegerSlider("Free Camera", "Camera Rolling Speed", 60, 10, 120, "Q/E rolling speed in degrees per second. This is not affected by Camera Speed, Shift, or Alt.", 30, showDefaultButton: false);
			InvertDroneMousePitch = ((BaseUnityPlugin)this).Config.Bind<bool>("Drone Mode", "Invert Mouse Pitch", false, new ConfigDescription("Invert vertical mouse input in Drone mode only.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			WaterCollision = ((BaseUnityPlugin)this).Config.Bind<bool>("Collision", "Water Collision", true, "Keep the camera sphere above the animated Crest water surface. Changes apply immediately.");
			SphereRadius = BindSlider("Collision Tuning", "Sphere Radius", 0.3f, 0.05f, 1.5f, "Radius used to sample and stay above the animated water surface.", 30);
			SurfacePadding = BindSlider("Collision Tuning", "Surface Padding", 0.1f, 0f, 0.5f, "Additional height kept between the camera sphere and the water surface.", 20);
		}

		private void RemoveObsoleteConfiguration()
		{
			try
			{
				if (!(OrphanedEntriesProperty?.GetValue(((BaseUnityPlugin)this).Config, null) is IDictionary<ConfigDefinition, string> dictionary))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not inspect obsolete configuration entries.");
					return;
				}
				bool flag = false;
				for (int i = 0; i < ObsoleteConfigDefinitions.Length; i++)
				{
					flag |= dictionary.Remove(ObsoleteConfigDefinitions[i]);
				}
				if (flag)
				{
					((BaseUnityPlugin)this).Config.Save();
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Removed obsolete solid-collision configuration.");
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not remove obsolete configuration entries: " + ex.GetBaseException().Message));
			}
		}

		private ConfigEntry<float> BindSlider(string section, string key, float defaultValue, float minimum, float maximum, string description, int order)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			return ((BaseUnityPlugin)this).Config.Bind<float>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(minimum, maximum), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					ShowRangeAsPercent = false,
					Order = order
				}
			}));
		}

		private ConfigEntry<int> BindIntegerSlider(string section, string key, int defaultValue, int minimum, int maximum, string description, int order, bool showDefaultButton)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			return ((BaseUnityPlugin)this).Config.Bind<int>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(minimum, maximum), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					ShowRangeAsPercent = false,
					HideDefaultButton = !showDefaultButton,
					Order = order
				}
			}));
		}

		private static void DrawMovementModeButtons(ConfigEntryBase setting)
		{
			if (!(setting is ConfigEntry<FreeCameraMovementMode> val))
			{
				return;
			}
			bool enabled = GUI.enabled;
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.enabled = enabled && val.Value > FreeCameraMovementMode.World;
			if (GUILayout.Button(WorldMovementButton, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }))
			{
				val.Value = FreeCameraMovementMode.World;
			}
			GUI.enabled = enabled && val.Value != FreeCameraMovementMode.Drone;
			if (GUILayout.Button(DroneMovementButton, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }))
			{
				val.Value = FreeCameraMovementMode.Drone;
			}
			GUILayout.EndHorizontal();
			GUI.enabled = enabled;
			if (val.Value == FreeCameraMovementMode.Drone && Instance?.InvertDroneMousePitch != null)
			{
				bool value = Instance.InvertDroneMousePitch.Value;
				bool flag = GUILayout.Toggle(value, InvertPitchToggle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				if (flag != value)
				{
					Instance.InvertDroneMousePitch.Value = flag;
				}
			}
			GUILayout.EndVertical();
		}
	}
}