Decompiled source of FroggosFPMotorcycle v1.0.0

Mods/Froggos-FP-Motorcycle.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using Il2CppFishNet.Object;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.AvatarFramework;
using Il2CppScheduleOne.AvatarFramework.Animation;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Vehicles;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using MotoFirstPerson;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(MfpMod), "MotoFirstPerson", "1.0.0", "froggonater", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: MelonOptionalDependencies(new string[] { "Chassis", "ScheduleIBikePack" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("MotoFirstPerson")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MotoFirstPerson")]
[assembly: AssemblyTitle("MotoFirstPerson")]
[assembly: AssemblyVersion("1.0.0.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 MotoFirstPerson
{
	internal static class ChassisBridge
	{
		private static bool _resolved;

		private static PropertyInfo _firstPersonActive;

		private static MethodInfo _profileFor;

		public static bool Installed { get; private set; }

		public static bool FirstPersonActive
		{
			get
			{
				if (!Installed || _firstPersonActive == null)
				{
					return false;
				}
				try
				{
					return (bool)_firstPersonActive.GetValue(null);
				}
				catch
				{
					return false;
				}
			}
		}

		public static void Resolve()
		{
			if (_resolved)
			{
				return;
			}
			_resolved = true;
			try
			{
				Type type = null;
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (!(assembly.GetName().Name != "Chassis"))
					{
						type = assembly.GetType("Chassis.Api.ChassisApi", throwOnError: false);
						if (type != null)
						{
							break;
						}
					}
				}
				if (!(type == null))
				{
					_firstPersonActive = type.GetProperty("FirstPersonActive", BindingFlags.Static | BindingFlags.Public);
					_profileFor = type.GetMethod("For", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(LandVehicle) }, null);
					Installed = true;
					MfpMod.Log.Msg($"Chassis found (FirstPersonActive {((_firstPersonActive != null) ? "ok" : "missing")}, For() {((_profileFor != null) ? "ok" : "missing")}). " + "Chassis keeps first person for its cars; this mod covers bikes and cars without a Chassis profile.");
				}
			}
			catch (Exception ex)
			{
				MfpMod.Log.Warning("Looking for Chassis failed, acting as if it is not installed: " + ex.Message);
				Installed = false;
			}
		}

		public static bool HasProfile(LandVehicle vehicle)
		{
			if (!Installed || _profileFor == null || (Object)(object)vehicle == (Object)null)
			{
				return false;
			}
			try
			{
				return _profileFor.Invoke(null, new object[1] { vehicle }) != null;
			}
			catch
			{
				return false;
			}
		}
	}
	internal enum RideKind
	{
		None,
		Bike,
		Car
	}
	internal static class FirstPersonCamera
	{
		private const float MaxYaw = 130f;

		private const float MinPitch = -70f;

		private const float MaxPitch = 65f;

		private const float MouseScale = 0.6f;

		private static readonly HashSet<string> BikeCodes = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "s1_offroad_motorcycle", "s1_street_motorcycle", "s1_cruiser_motorcycle", "s1_offroad_bicycle", "s1_street_bicycle" };

		private static RideKind _kind;

		private static LandVehicle _vehicle;

		private static LandVehicle _lastVehicle;

		private static bool _wantFirstPerson;

		private static float _yaw;

		private static float _pitch;

		private static float _savedNearClip = -1f;

		private static AvatarEffects _effects;

		private static bool _disableHeadBefore;

		private static IntPtr _localAnimPtr;

		private static readonly List<KeyValuePair<Renderer, ShadowCastingMode>> _hidden = new List<KeyValuePair<Renderer, ShadowCastingMode>>();

		private static bool _announced;

		private static bool _headMissingLogged;

		private static bool _placeFailed;

		public static bool Active { get; private set; }

		public static bool IsBikeCode(string code)
		{
			if (string.IsNullOrEmpty(code))
			{
				return false;
			}
			if (!BikeCodes.Contains(code) && !code.EndsWith("_motorcycle", StringComparison.OrdinalIgnoreCase))
			{
				return code.EndsWith("_bicycle", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		private static LandVehicle CurrentVehicle(Player local)
		{
			if ((Object)(object)local == (Object)null || !local.IsInVehicle)
			{
				return null;
			}
			NetworkObject currentVehicle = local.CurrentVehicle;
			if ((Object)(object)currentVehicle == (Object)null)
			{
				return null;
			}
			return ((Component)currentVehicle).GetComponent<LandVehicle>();
		}

		private static RideKind Classify(LandVehicle lv)
		{
			if ((Object)(object)lv == (Object)null)
			{
				return RideKind.None;
			}
			if (ChassisBridge.HasProfile(lv))
			{
				return RideKind.None;
			}
			if (IsBikeCode(lv.vehicleCode))
			{
				return RideKind.Bike;
			}
			if (!MfpMod.Cfg.CarsWithoutChassis.Value)
			{
				return RideKind.None;
			}
			return RideKind.Car;
		}

		public static void Tick()
		{
			//IL_00cd: 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_0179: Invalid comparison between Unknown and I4
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: 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)
			LandVehicle val = CurrentVehicle(Player.Local);
			if ((Object)(object)val != (Object)(object)_lastVehicle)
			{
				if (Active)
				{
					Set(on: false, "changed vehicle");
				}
				_lastVehicle = val;
				if ((Object)(object)val != (Object)null && MfpMod.Cfg.RememberView.Value && _wantFirstPerson && Classify(val) != RideKind.None)
				{
					Set(on: true, "remembered view");
				}
			}
			if (Active && ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)_vehicle))
			{
				Set(on: false, "not riding");
			}
			else if (Active && ChassisBridge.FirstPersonActive)
			{
				Set(on: false, "Chassis first person took over");
			}
			else
			{
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				if (!GameInput.IsTyping)
				{
					Keyboard current = Keyboard.current;
					if (current != null && ((ButtonControl)current[MfpMod.Cfg.Toggle]).wasPressedThisFrame)
					{
						if (Active)
						{
							Set(on: false, $"{MfpMod.Cfg.Toggle} pressed");
						}
						else if (Classify(val) != RideKind.None)
						{
							Set(on: true, $"{MfpMod.Cfg.Toggle} pressed");
						}
						_wantFirstPerson = Active;
					}
				}
				if (Active && !GameInput.IsTyping && (int)Cursor.lockState == 1)
				{
					float num = 0.6f * MfpMod.Cfg.LookSensitivity.Value;
					if (Singleton<Settings>.InstanceExists)
					{
						num *= Singleton<Settings>.Instance.LookSensitivity;
					}
					Vector2 mouseDelta = GameInput.MouseDelta;
					_yaw = Mathf.Clamp(_yaw + mouseDelta.x * num, -130f, 130f);
					_pitch = Mathf.Clamp(_pitch - mouseDelta.y * num, -70f, 65f);
				}
			}
		}

		public static void Reset()
		{
			if (Active)
			{
				Set(on: false, "world unloaded");
			}
			_lastVehicle = null;
		}

		public static void Set(bool on, string why)
		{
			if (on == Active)
			{
				return;
			}
			Player local = Player.Local;
			if (on)
			{
				LandVehicle val = CurrentVehicle(local);
				RideKind rideKind = Classify(val);
				if (rideKind == RideKind.None)
				{
					return;
				}
				_vehicle = val;
				_kind = rideKind;
			}
			Active = on;
			_yaw = 0f;
			_pitch = 0f;
			_announced = false;
			_placeFailed = false;
			Camera val2 = (PlayerSingleton<PlayerCamera>.InstanceExists ? PlayerSingleton<PlayerCamera>.Instance.Camera : null);
			if ((Object)(object)val2 != (Object)null)
			{
				if (on)
				{
					_savedNearClip = val2.nearClipPlane;
					val2.nearClipPlane = Mathf.Min(val2.nearClipPlane, MfpMod.Cfg.NearClip.Value);
				}
				else if (_savedNearClip > 0f)
				{
					val2.nearClipPlane = _savedNearClip;
				}
			}
			if (on)
			{
				Avatar val3 = (((Object)(object)local != (Object)null) ? local.Avatar : null);
				_localAnimPtr = (((Object)(object)val3 != (Object)null && (Object)(object)val3.Animation != (Object)null) ? ((Il2CppObjectBase)val3.Animation).Pointer : IntPtr.Zero);
				if (_kind == RideKind.Bike)
				{
					HideHead(val3);
				}
			}
			else
			{
				ShowHead();
				_vehicle = null;
				_kind = RideKind.None;
				_localAnimPtr = IntPtr.Zero;
			}
			string value = ((on && (Object)(object)_vehicle != (Object)null) ? _vehicle.vehicleCode : "");
			MfpMod.Log.Msg($"First person {(on ? "on" : "off")} ({why}){(on ? $" on {value} as {_kind}" : "")}.");
		}

		private static void HideHead(Avatar avatar)
		{
			//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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Invalid comparison between Unknown and I4
			//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_0093: 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_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_00c3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)avatar == (Object)null)
			{
				return;
			}
			_effects = avatar.Effects;
			Transform val = null;
			if ((Object)(object)_effects != (Object)null)
			{
				_disableHeadBefore = _effects.DisableHead;
				_effects.DisableHead = true;
				val = _effects.HeadBone;
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Vector3 position = val.position;
			foreach (Renderer componentsInChild in ((Component)avatar).GetComponentsInChildren<Renderer>())
			{
				if ((Object)(object)componentsInChild == (Object)null || !componentsInChild.enabled || (int)componentsInChild.shadowCastingMode == 3)
				{
					continue;
				}
				Bounds bounds = componentsInChild.bounds;
				if (!(Vector3.Distance(((Bounds)(ref bounds)).center, position) > 0.3f))
				{
					Vector3 extents = ((Bounds)(ref bounds)).extents;
					if (!(((Vector3)(ref extents)).magnitude > 0.4f))
					{
						_hidden.Add(new KeyValuePair<Renderer, ShadowCastingMode>(componentsInChild, componentsInChild.shadowCastingMode));
						componentsInChild.shadowCastingMode = (ShadowCastingMode)3;
					}
				}
			}
			if (MfpMod.Cfg.VerboseLog.Value)
			{
				MfpMod.Log.Msg($"Head hidden: DisableHead set, {_hidden.Count} head part(s) shadow-only.");
			}
		}

		private static void ShowHead()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_effects != (Object)null)
			{
				_effects.DisableHead = _disableHeadBefore;
			}
			_effects = null;
			foreach (KeyValuePair<Renderer, ShadowCastingMode> item in _hidden)
			{
				if ((Object)(object)item.Key != (Object)null)
				{
					item.Key.shadowCastingMode = item.Value;
				}
			}
			_hidden.Clear();
		}

		public static void Place(string from)
		{
			//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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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)
			//IL_0050: 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_0084: 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_0090: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: 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_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: 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)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: 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_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: 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_01d5: 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_020e: 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)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: 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_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || (Object)(object)_vehicle == (Object)null)
			{
				return;
			}
			try
			{
				if (!PlayerSingleton<PlayerCamera>.InstanceExists)
				{
					return;
				}
				Player local = Player.Local;
				if ((Object)(object)local == (Object)null)
				{
					return;
				}
				Transform transform = ((Component)_vehicle).transform;
				Quaternion rotation = transform.rotation;
				Quaternion val = rotation;
				Vector3 forward = transform.forward;
				float num = Mathf.Clamp01(MfpMod.Cfg.FollowLean.Value);
				if (num < 0.999f && Mathf.Abs(forward.y) < 0.95f)
				{
					val = Quaternion.Slerp(Quaternion.LookRotation(forward, Vector3.up), rotation, num);
				}
				Vector3 val3;
				if (_kind == RideKind.Bike)
				{
					Transform val2 = HeadOf(local);
					if ((Object)(object)val2 != (Object)null)
					{
						val3 = val2.position + rotation * new Vector3(0f, MfpMod.Cfg.BikeEyeUp.Value, MfpMod.Cfg.BikeEyeForward.Value);
					}
					else
					{
						if (!_headMissingLogged)
						{
							_headMissingLogged = true;
							MfpMod.Log.Warning("Rider head bone not found; using a fixed eye point above the bike instead.");
						}
						val3 = transform.TransformPoint(new Vector3(0f, 1.45f, -0.15f));
					}
				}
				else
				{
					Transform val4 = SeatOf(local, _vehicle);
					val3 = (((Object)(object)val4 != (Object)null) ? val4.position : transform.position) + rotation * new Vector3(0f, MfpMod.Cfg.CarEyeUp.Value, MfpMod.Cfg.CarEyeForward.Value);
				}
				Quaternion val5 = val * Quaternion.Euler(0f, _yaw, 0f) * Quaternion.Euler(_pitch, 0f, 0f);
				PlayerCamera instance = PlayerSingleton<PlayerCamera>.Instance;
				Transform transform2 = ((Component)instance).transform;
				transform2.SetPositionAndRotation(val3, val5);
				Transform val6 = (((Object)(object)instance.Camera != (Object)null) ? ((Component)instance.Camera).transform : transform2);
				if ((Object)(object)val6 != (Object)(object)transform2)
				{
					transform2.rotation = val5 * Quaternion.Inverse(val6.rotation) * transform2.rotation;
					transform2.position += val3 - val6.position;
				}
				if (!_announced)
				{
					_announced = true;
					if (MfpMod.Cfg.VerboseLog.Value)
					{
						Instance log = MfpMod.Log;
						DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(77, 5);
						defaultInterpolatedStringHandler.AppendLiteral("Camera placed from ");
						defaultInterpolatedStringHandler.AppendFormatted(from);
						defaultInterpolatedStringHandler.AppendLiteral(": eye ");
						defaultInterpolatedStringHandler.AppendFormatted<Vector3>(val3, "F2");
						defaultInterpolatedStringHandler.AppendLiteral(" (vehicle-local ");
						defaultInterpolatedStringHandler.AppendFormatted<Vector3>(transform.InverseTransformPoint(val3), "F2");
						defaultInterpolatedStringHandler.AppendLiteral("), ");
						defaultInterpolatedStringHandler.AppendLiteral("vehicle rot ");
						Quaternion rotation2 = transform.rotation;
						defaultInterpolatedStringHandler.AppendFormatted<Vector3>(((Quaternion)(ref rotation2)).eulerAngles, "F0");
						defaultInterpolatedStringHandler.AppendLiteral(", lens ");
						defaultInterpolatedStringHandler.AppendFormatted(((Object)(object)val6 == (Object)(object)transform2) ? "is" : "under");
						defaultInterpolatedStringHandler.AppendLiteral(" PlayerCamera.");
						log.Msg(defaultInterpolatedStringHandler.ToStringAndClear());
					}
				}
				_placeFailed = false;
			}
			catch (Exception ex)
			{
				if (!_placeFailed)
				{
					MfpMod.Log.Error("Placing the first person camera failed, back to the normal camera: " + ex);
				}
				_placeFailed = true;
				Set(on: false, "camera error");
			}
		}

		private static Transform HeadOf(Player local)
		{
			Avatar avatar = local.Avatar;
			if ((Object)(object)avatar == (Object)null)
			{
				return null;
			}
			AvatarEffects effects = avatar.Effects;
			if (!((Object)(object)effects != (Object)null))
			{
				return null;
			}
			return effects.HeadBone;
		}

		private static Transform SeatOf(Player local, LandVehicle lv)
		{
			VehicleSeat localPlayerSeat = lv.localPlayerSeat;
			if ((Object)(object)localPlayerSeat != (Object)null)
			{
				return ((Component)localPlayerSeat).transform;
			}
			Il2CppReferenceArray<VehicleSeat> seats = lv.Seats;
			if (seats == null)
			{
				return null;
			}
			foreach (VehicleSeat item in (Il2CppArrayBase<VehicleSeat>)(object)seats)
			{
				if ((Object)(object)item != (Object)null && (Object)(object)item.Occupant != (Object)null && ((Il2CppObjectBase)item.Occupant).Pointer == ((Il2CppObjectBase)local).Pointer)
				{
					return ((Component)item).transform;
				}
			}
			return null;
		}

		public static bool IsLocalAnimation(AvatarAnimation anim)
		{
			if (Active && _kind == RideKind.Bike && (Object)(object)anim != (Object)null && _localAnimPtr != IntPtr.Zero)
			{
				return ((Il2CppObjectBase)anim).Pointer == _localAnimPtr;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(VehicleCamera), "LateUpdate")]
	internal static class VehicleCameraLatePatch
	{
		[HarmonyPriority(0)]
		private static void Postfix()
		{
			if (FirstPersonCamera.Active)
			{
				FirstPersonCamera.Place("vehicle camera");
			}
		}
	}
	[HarmonyPatch(typeof(AvatarAnimation), "LateUpdate")]
	internal static class AvatarAnimationLatePatch
	{
		[HarmonyPriority(0)]
		private static void Postfix(AvatarAnimation __instance)
		{
			if (FirstPersonCamera.IsLocalAnimation(__instance))
			{
				FirstPersonCamera.Place("rider pose");
			}
		}
	}
	[HarmonyPatch(typeof(Player), "ExitVehicle")]
	internal static class ExitVehiclePatch
	{
		private static void Prefix(Player __instance)
		{
			try
			{
				if ((Object)(object)__instance != (Object)null && __instance.IsLocalPlayer && FirstPersonCamera.Active)
				{
					FirstPersonCamera.Set(on: false, "exited vehicle");
				}
			}
			catch (Exception ex)
			{
				MfpMod.Log.Error("Leaving first person on exit failed: " + ex.Message);
			}
		}
	}
	internal class MfpConfig
	{
		public readonly MelonPreferences_Category Category;

		public readonly MelonPreferences_Entry<string> ToggleKey;

		public readonly MelonPreferences_Entry<bool> RememberView;

		public readonly MelonPreferences_Entry<bool> CarsWithoutChassis;

		public readonly MelonPreferences_Entry<float> FollowLean;

		public readonly MelonPreferences_Entry<float> LookSensitivity;

		public readonly MelonPreferences_Entry<float> BikeEyeUp;

		public readonly MelonPreferences_Entry<float> BikeEyeForward;

		public readonly MelonPreferences_Entry<float> CarEyeUp;

		public readonly MelonPreferences_Entry<float> CarEyeForward;

		public readonly MelonPreferences_Entry<float> NearClip;

		public readonly MelonPreferences_Entry<bool> VerboseLog;

		public Key Toggle { get; private set; } = (Key)36;

		public MfpConfig()
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: 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)
			Category = MelonPreferences.CreateCategory("MotoFirstPerson", "MotoFirstPerson");
			ToggleKey = Category.CreateEntry<string>("ToggleKey", "V", (string)null, "Key that switches first person on/off while riding (UnityEngine.InputSystem.Key name, e.g. V, F6, C). V matches Chassis.", false, false, (ValueValidator)null, (string)null);
			RememberView = Category.CreateEntry<bool>("RememberView", true, (string)null, "Start in first person when you get on a bike if you left the last one in first person.", false, false, (ValueValidator)null, (string)null);
			CarsWithoutChassis = Category.CreateEntry<bool>("CarsWithoutChassis", true, (string)null, "Also give cars a first person view when Chassis is not installed (or has no profile for that car). With Chassis installed, its own view is used for its cars.", false, false, (ValueValidator)null, (string)null);
			FollowLean = Category.CreateEntry<float>("FollowLean", 1f, (string)null, "How much the view tilts with the bike in corners: 0 = horizon stays level, 1 = lean fully with the bike.", false, false, (ValueValidator)null, (string)null);
			LookSensitivity = Category.CreateEntry<float>("LookSensitivity", 1f, (string)null, "Mouse look speed in first person (multiplied by the game's own look sensitivity).", false, false, (ValueValidator)null, (string)null);
			BikeEyeUp = Category.CreateEntry<float>("BikeEyeUp", 0.08f, (string)null, "Bikes: eye height above the rider's head bone (meters).", false, false, (ValueValidator)null, (string)null);
			BikeEyeForward = Category.CreateEntry<float>("BikeEyeForward", 0.1f, (string)null, "Bikes: eye distance in front of the rider's head bone (meters).", false, false, (ValueValidator)null, (string)null);
			CarEyeUp = Category.CreateEntry<float>("CarEyeUp", 0.7f, (string)null, "Cars without Chassis: eye height above the seat point (meters).", false, false, (ValueValidator)null, (string)null);
			CarEyeForward = Category.CreateEntry<float>("CarEyeForward", 0f, (string)null, "Cars without Chassis: eye offset forward from the seat point (meters).", false, false, (ValueValidator)null, (string)null);
			NearClip = Category.CreateEntry<float>("NearClip", 0.03f, (string)null, "Camera near clip plane in first person, so the handlebars/dashboard right in front of you are not cut off.", false, false, (ValueValidator)null, (string)null);
			VerboseLog = Category.CreateEntry<bool>("VerboseLog", false, (string)null, "Log extra detail (camera placement) for troubleshooting.", false, false, (ValueValidator)null, (string)null);
			if (Enum.TryParse<Key>(ToggleKey.Value?.Trim(), ignoreCase: true, out Key result) && (int)result != 0)
			{
				Toggle = result;
			}
			else
			{
				MfpMod.Log.Warning("ToggleKey '" + ToggleKey.Value + "' is not a valid key name, using V.");
			}
		}
	}
	public class MfpMod : MelonMod
	{
		internal static Instance Log;

		internal static MfpConfig Cfg;

		private static bool _tickFailed;

		public override void OnInitializeMelon()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			Log = ((MelonBase)this).LoggerInstance;
			Cfg = new MfpConfig();
			Log.Msg($"MotoFirstPerson loaded. Press [{Cfg.Toggle}] on a motorcycle for first person.");
		}

		public override void OnLateInitializeMelon()
		{
			ChassisBridge.Resolve();
			if (!ChassisBridge.Installed)
			{
				Log.Msg(Cfg.CarsWithoutChassis.Value ? "Chassis not installed: this mod also gives cars a first person view." : "Chassis not installed and CarsWithoutChassis is off: first person on bikes only.");
			}
		}

		public override void OnUpdate()
		{
			try
			{
				FirstPersonCamera.Tick();
				_tickFailed = false;
			}
			catch (Exception ex)
			{
				if (!_tickFailed)
				{
					Log.Error("Update failed (logged once until it works again): " + ex);
				}
				_tickFailed = true;
			}
		}

		public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
		{
			FirstPersonCamera.Reset();
		}
	}
}