Decompiled source of BigChoppa v1.0.2

BigChoppa.dll

Decompiled 4 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using Mirror;
using Rewired;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BigChoppa")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+4e223f5a2725ed08cb9ce3d84465d45f259c5bc5")]
[assembly: AssemblyProduct("BigChoppa")]
[assembly: AssemblyTitle("BigChoppa")]
[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.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 BigChoppa
{
	internal static class ChoppaAudio
	{
		private const int Rate = 44100;

		private static AudioClip rotorClip;

		private static AudioClip turbineClip;

		private static AudioClip[] bonkClips;

		private static AudioMixerGroup mixerGroup;

		private static bool mixerSearched;

		public static void Attach(Helicopter heli)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			//IL_003a: 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)
			if (EnsureClips())
			{
				GameObject val = new GameObject("Audio");
				val.transform.SetParent(((Component)heli).transform, false);
				val.transform.localPosition = new Vector3(0f, 2.5f, 0f) * ChoppaConfig.HeliScale.Value;
				heli.RotorAudio = Loop(val, rotorClip, 12f);
				heli.TurbineAudio = Loop(val, turbineClip, 6f);
			}
		}

		private static AudioSource Loop(GameObject go, AudioClip clip, float minDistance)
		{
			AudioSource obj = go.AddComponent<AudioSource>();
			Setup(obj, minDistance);
			obj.clip = clip;
			obj.loop = true;
			obj.volume = 0f;
			return obj;
		}

		private static void Setup(AudioSource s, float minDistance)
		{
			s.playOnAwake = false;
			s.spatialBlend = 1f;
			s.rolloffMode = (AudioRolloffMode)0;
			s.minDistance = minDistance * ChoppaConfig.HeliScale.Value;
			s.maxDistance = ChoppaConfig.AudioMaxDistance.Value;
			s.dopplerLevel = 0.6f;
			s.spread = 60f;
			s.priority = 64;
			AudioMixerGroup val = MixerGroup();
			if ((Object)(object)val != (Object)null)
			{
				s.outputAudioMixerGroup = val;
			}
		}

		public static void Drive(Helicopter h)
		{
			if ((Object)(object)h.RotorAudio == (Object)null || (Object)(object)h.TurbineAudio == (Object)null)
			{
				return;
			}
			float value = ChoppaConfig.AudioVolume.Value;
			float num = (h.Broken ? 0f : h.RotorSpin);
			float collective = h.Collective;
			bool flag = num > 0.005f && value > 0f;
			AudioSource[] array = (AudioSource[])(object)new AudioSource[2] { h.RotorAudio, h.TurbineAudio };
			foreach (AudioSource val in array)
			{
				if (flag && !val.isPlaying)
				{
					val.time = Random.value * val.clip.length * 0.99f;
					val.Play();
				}
				else if (!flag && val.isPlaying)
				{
					val.Stop();
				}
			}
			if (flag)
			{
				h.RotorAudio.volume = value * Mathf.Pow(num, 1.3f) * (0.55f + 0.45f * collective);
				h.RotorAudio.pitch = 0.35f + 0.65f * num + 0.1f * (collective - 0.5f) * num;
				h.TurbineAudio.volume = value * 0.12f * Mathf.Pow(num, 0.7f);
				h.TurbineAudio.pitch = 0.4f + 0.6f * num + 0.1f * collective;
			}
		}

		public static void Bonk(AudioSource src, float impactSpeed, float size)
		{
			float value = ChoppaConfig.AudioVolume.Value;
			if (!(value <= 0f) && !((Object)(object)src == (Object)null) && EnsureClips())
			{
				float num = Mathf.Clamp01((impactSpeed - 0.5f) / 8f);
				if (!(num <= 0.02f))
				{
					src.pitch = Mathf.Lerp(1.35f, 0.55f, size) * Random.Range(0.9f, 1.1f);
					src.PlayOneShot(bonkClips[Random.Range(0, bonkClips.Length)], value * num * Mathf.Lerp(0.6f, 1f, size));
				}
			}
		}

		public static AudioSource OneShotSource(GameObject go, float minDistance)
		{
			AudioSource obj = go.AddComponent<AudioSource>();
			Setup(obj, minDistance);
			obj.loop = false;
			return obj;
		}

		public static void PlayCrash(Vector3 position)
		{
			//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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0053: Expected O, but got Unknown
			if (!(ChoppaConfig.AudioVolume.Value <= 0f) && EnsureClips())
			{
				GameObject val = new GameObject("ChoppaCrashSound");
				val.transform.position = position;
				Bonk(OneShotSource(val, 15f), 20f, 1f);
				Object.Destroy((Object)val, 2f);
			}
		}

		private static AudioMixerGroup MixerGroup()
		{
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			if ((Object)(object)mixerGroup != (Object)null && !((Il2CppObjectBase)mixerGroup).WasCollected)
			{
				return mixerGroup;
			}
			if (mixerSearched)
			{
				return null;
			}
			mixerSearched = true;
			bool flag = default(bool);
			try
			{
				Dictionary<string, (AudioMixerGroup, int)> dictionary = new Dictionary<string, (AudioMixerGroup, int)>();
				foreach (AudioSource item in Object.FindObjectsByType<AudioSource>((FindObjectsInactive)1, (FindObjectsSortMode)0))
				{
					AudioMixerGroup outputAudioMixerGroup = item.outputAudioMixerGroup;
					if (!((Object)(object)outputAudioMixerGroup == (Object)null))
					{
						dictionary[((Object)outputAudioMixerGroup).name] = (dictionary.TryGetValue(((Object)outputAudioMixerGroup).name, out var value) ? (outputAudioMixerGroup, value.Item2 + 1) : (outputAudioMixerGroup, 1));
					}
				}
				Plugin.Verbose("Game mixer groups: " + string.Join(", ", dictionary.Select<KeyValuePair<string, (AudioMixerGroup, int)>, string>((KeyValuePair<string, (AudioMixerGroup g, int n)> kv) => $"{kv.Key}x{kv.Value.n}")));
				string text = null;
				foreach (KeyValuePair<string, (AudioMixerGroup, int)> item2 in dictionary)
				{
					if (Score(item2.Key) >= 0 && (text == null || Score(item2.Key) > Score(text) || (Score(item2.Key) == Score(text) && item2.Value.Item2 > dictionary[text].Item2)))
					{
						text = item2.Key;
					}
				}
				if (text != null)
				{
					mixerGroup = dictionary[text].Item1;
					ManualLogSource l = Plugin.L;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(38, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Choppa audio routed to mixer group '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'.");
					}
					l.LogInfo(val);
				}
				else
				{
					Plugin.L.LogInfo((object)"No game mixer group found; choppa audio plays direct.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource l2 = Plugin.L;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(27, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Mixer group search failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				l2.LogWarning(val2);
			}
			return mixerGroup;
			static int Score(string name)
			{
				string text2 = name.ToLowerInvariant();
				if (text2.Contains("music") || text2.Contains("ui") || text2.Contains("voice") || text2.Contains("amb"))
				{
					return -1;
				}
				if (text2.Contains("sfx") || text2.Contains("effect"))
				{
					return 3;
				}
				if (text2.Contains("world") || text2.Contains("game") || text2.Contains("prop"))
				{
					return 2;
				}
				return 1;
			}
		}

		private static bool EnsureClips()
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			try
			{
				if (Dead(rotorClip))
				{
					rotorClip = MakeClip("ChoppaRotor", SynthRotor());
				}
				if (Dead(turbineClip))
				{
					turbineClip = MakeClip("ChoppaTurbine", SynthTurbine());
				}
				if (bonkClips == null || Array.Exists(bonkClips, Dead))
				{
					bonkClips = (AudioClip[])(object)new AudioClip[4];
					for (int i = 0; i < bonkClips.Length; i++)
					{
						bonkClips[i] = MakeClip($"ChoppaBonk{i}", SynthBonk(i));
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(31, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Choppa audio synthesis failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				l.LogError(val);
				return false;
			}
		}

		private static bool Dead(AudioClip c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				return ((Il2CppObjectBase)c).WasCollected;
			}
			return true;
		}

		private static AudioClip MakeClip(string name, float[] data)
		{
			Normalize(data, 0.9f);
			AudioClip obj = AudioClip.Create(name, data.Length, 1, 44100, false);
			obj.SetData(Il2CppStructArray<float>.op_Implicit(data), 0);
			((Object)obj).hideFlags = (HideFlags)32;
			return obj;
		}

		private static float[] SynthRotor()
		{
			int num = 44100;
			Random rng = new Random(1234);
			float[] array = LowPassLoop(WhiteNoise(num, rng), 420f);
			float[] array2 = LowPassLoop(WhiteNoise(num, rng), 120f);
			float[] array3 = new float[num];
			int num2 = num / 10;
			for (int i = 0; i < num; i++)
			{
				float num3 = (float)(i % num2) / 44100f;
				float num4 = Mathf.Exp((0f - num3) / 0.035f) * Mathf.Clamp01(num3 / 0.003f);
				float num5 = Mathf.Sin((float)Math.PI * 140f * num3) * Mathf.Exp((0f - num3) / 0.05f);
				array3[i] = num4 * array[i] * 2.2f + num5 * 0.7f + array2[i] * 1.2f;
			}
			return array3;
		}

		private static float[] SynthTurbine()
		{
			int num = 44100;
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				float num2 = (float)i / 44100f;
				float num3 = 0.5f + 0.5f * Mathf.Sin((float)Math.PI * 68f * num2);
				array[i] = Mathf.Sin((float)Math.PI * 1240f * num2) * num3;
			}
			return array;
		}

		private static float[] SynthBonk(int variant)
		{
			int num = 15435;
			Random rng = new Random(500 + variant);
			float num2 = 260f + (float)variant * 70f;
			float[] array = LowPass(WhiteNoise(num, rng), 3000f);
			float[] array2 = new float[num];
			double num3 = 0.0;
			double num4 = 0.0;
			for (int i = 0; i < num; i++)
			{
				float num5 = (float)i / 44100f;
				float num6 = num2 * (1f + 0.6f * Mathf.Exp((0f - num5) / 0.012f));
				num3 += Math.PI * 2.0 * (double)num6 / 44100.0;
				num4 += Math.PI * 2.0 * (double)num6 * 2.31 / 44100.0;
				float num7 = Mathf.Exp((0f - num5) / 0.07f) * Mathf.Clamp01(num5 / 0.001f);
				array2[i] = num7 * ((float)Math.Sin(num3) + 0.35f * (float)Math.Sin(num4) * Mathf.Exp((0f - num5) / 0.03f)) + array[i] * 1.5f * Mathf.Exp((0f - num5) / 0.004f);
			}
			return array2;
		}

		private static float[] WhiteNoise(int n, Random rng)
		{
			float[] array = new float[n];
			for (int i = 0; i < n; i++)
			{
				array[i] = (float)(rng.NextDouble() * 2.0 - 1.0);
			}
			return array;
		}

		private static float[] LowPass(float[] x, float cutoff)
		{
			float num = 1f - Mathf.Exp((float)Math.PI * -2f * cutoff / 44100f);
			float[] array = new float[x.Length];
			float num2 = 0f;
			for (int i = 0; i < x.Length; i++)
			{
				num2 = (array[i] = num2 + num * (x[i] - num2));
			}
			return array;
		}

		private static float[] LowPassLoop(float[] x, float cutoff)
		{
			float num = 1f - Mathf.Exp((float)Math.PI * -2f * cutoff / 44100f);
			float[] array = new float[x.Length];
			float num2 = 0f;
			for (int i = 0; i < 2; i++)
			{
				for (int j = 0; j < x.Length; j++)
				{
					num2 = (array[j] = num2 + num * (x[j] - num2));
				}
			}
			return array;
		}

		private static void Normalize(float[] d, float peak)
		{
			float num = 1E-06f;
			foreach (float num2 in d)
			{
				num = Mathf.Max(num, Mathf.Abs(num2));
			}
			float num3 = peak / num;
			for (int j = 0; j < d.Length; j++)
			{
				d[j] *= num3;
			}
		}
	}
	public class ChoppaBonker : MonoBehaviour
	{
		public AudioSource Source;

		public float Size = 0.5f;

		public float MinSpeed = 1f;

		private float nextAllowed;

		private static float windowStart;

		private static int windowCount;

		public ChoppaBonker(IntPtr ptr)
			: base(ptr)
		{
		}

		public static ChoppaBonker Add(GameObject go, float size, float minSpeed)
		{
			ChoppaBonker choppaBonker = go.AddComponent<ChoppaBonker>();
			choppaBonker.Size = size;
			choppaBonker.MinSpeed = minSpeed;
			choppaBonker.Source = ChoppaAudio.OneShotSource(go, 4f + 6f * size);
			return choppaBonker;
		}

		private void OnCollisionEnter(Collision c)
		{
			//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)
			Vector3 relativeVelocity = c.relativeVelocity;
			float magnitude = ((Vector3)(ref relativeVelocity)).magnitude;
			if (!(magnitude < MinSpeed) && !(Time.time < nextAllowed))
			{
				nextAllowed = Time.time + 0.08f;
				if (Time.time - windowStart > 0.1f)
				{
					windowStart = Time.time;
					windowCount = 0;
				}
				if (++windowCount <= 12)
				{
					ChoppaAudio.Bonk(Source, magnitude, Size);
				}
			}
		}
	}
	internal enum InputBackend
	{
		Auto,
		Rewired,
		Unity
	}
	internal static class ChoppaConfig
	{
		public static ConfigEntry<KeyCode> CollectiveUpKey;

		public static ConfigEntry<KeyCode> CollectiveDownKey;

		public static ConfigEntry<KeyCode> PedalLeftKey;

		public static ConfigEntry<KeyCode> PedalRightKey;

		public static ConfigEntry<KeyCode> SpawnKey;

		public static ConfigEntry<KeyCode> EnterExitKey;

		public static ConfigEntry<KeyCode> ResetKey;

		public static ConfigEntry<KeyCode> CameraKey;

		public static ConfigEntry<KeyCode> FreeLookKey;

		public static ConfigEntry<KeyCode> HudKey;

		public static ConfigEntry<float> MouseSensitivity;

		public static ConfigEntry<bool> InvertPitch;

		public static ConfigEntry<bool> InvertRoll;

		public static ConfigEntry<InputBackend> Backend;

		public static ConfigEntry<bool> RequireCursorLock;

		public static ConfigEntry<float> MaxLiftG;

		public static ConfigEntry<float> CollectiveRate;

		public static ConfigEntry<float> MaxPitchRollRate;

		public static ConfigEntry<float> YawRate;

		public static ConfigEntry<float> ControlResponse;

		public static ConfigEntry<float> MouseSmoothing;

		public static ConfigEntry<float> AutoLevel;

		public static ConfigEntry<float> Weathervane;

		public static ConfigEntry<float> SpinUpSeconds;

		public static ConfigEntry<float> ForwardDrag;

		public static ConfigEntry<float> SideDrag;

		public static ConfigEntry<float> VerticalDrag;

		public static ConfigEntry<float> LinearDrag;

		public static ConfigEntry<float> Mass;

		public static ConfigEntry<float> CenterOfMassHeight;

		public static ConfigEntry<bool> CollectiveSpringBack;

		public static ConfigEntry<bool> HoverTiltCompensation;

		public static ConfigEntry<float> CollectiveReturnRate;

		public static ConfigEntry<bool> BreakApart;

		public static ConfigEntry<float> CrashDeltaV;

		public static ConfigEntry<float> CrashBlast;

		public static ConfigEntry<float> DebrisSeconds;

		public static ConfigEntry<float> CrashStunRadius;

		public static ConfigEntry<float> HeliScale;

		public static ConfigEntry<float> SeatHeightOffset;

		public static ConfigEntry<float> SeatForwardOffset;

		public static ConfigEntry<float> EnterDistance;

		public static ConfigEntry<float> ChaseDistance;

		public static ConfigEntry<float> ChaseHeight;

		public static ConfigEntry<float> CockpitEyeHeight;

		public static ConfigEntry<bool> SitWhileFlying;

		public static ConfigEntry<int> ChoppaLayer;

		public static ConfigEntry<float> AudioVolume;

		public static ConfigEntry<float> AudioMaxDistance;

		public static ConfigEntry<bool> LogbookEnabled;

		public static ConfigEntry<string> LogbookInstallId;

		public static ConfigEntry<bool> NetEnabled;

		public static ConfigEntry<float> NetSendRate;

		public static ConfigEntry<float> NetInterpDelay;

		public static ConfigEntry<bool> ShowHud;

		public static ConfigEntry<bool> VerboseLogging;

		public static void Bind(ConfigFile cfg)
		{
			CollectiveUpKey = cfg.Bind<KeyCode>("Controls", "CollectiveUp", (KeyCode)119, "Hold to raise collective (more lift).");
			CollectiveDownKey = cfg.Bind<KeyCode>("Controls", "CollectiveDown", (KeyCode)115, "Hold to lower collective (less lift).");
			PedalLeftKey = cfg.Bind<KeyCode>("Controls", "PedalLeft", (KeyCode)97, "Left anti-torque pedal (yaw left).");
			PedalRightKey = cfg.Bind<KeyCode>("Controls", "PedalRight", (KeyCode)100, "Right anti-torque pedal (yaw right).");
			SpawnKey = cfg.Bind<KeyCode>("Controls", "Spawn", (KeyCode)289, "Spawn a choppa in front of you (replaces your previous one if nobody is in it).");
			EnterExitKey = cfg.Bind<KeyCode>("Controls", "EnterExit", (KeyCode)103, "Board or leave the choppa.");
			ResetKey = cfg.Bind<KeyCode>("Controls", "ResetUpright", (KeyCode)290, "Flip the choppa back upright where it is.");
			CameraKey = cfg.Bind<KeyCode>("Controls", "ToggleCamera", (KeyCode)118, "Switch between chase and cockpit camera.");
			FreeLookKey = cfg.Bind<KeyCode>("Controls", "FreeLook", (KeyCode)308, "Hold to look around with the mouse instead of flying with it.");
			HudKey = cfg.Bind<KeyCode>("Controls", "ToggleHud", (KeyCode)291, "Show/hide the flight HUD.");
			MouseSensitivity = cfg.Bind<float>("Controls", "MouseSensitivity", 0.3f, "Degrees of pitch/roll per unit of mouse movement. Mouse forward = nose down, mouse left = roll left.");
			InvertPitch = cfg.Bind<bool>("Controls", "InvertPitch", false, "Swap mouse forward/back for pitch.");
			InvertRoll = cfg.Bind<bool>("Controls", "InvertRoll", false, "Swap mouse left/right for roll.");
			Backend = cfg.Bind<InputBackend>("Controls", "InputBackend", InputBackend.Auto, "Where to read keys/mouse from. Auto tries the game's Rewired input first, then Unity's legacy Input.");
			RequireCursorLock = cfg.Bind<bool>("Controls", "RequireCursorLock", true, "Ignore flight inputs while the cursor is unlocked (menus open).");
			MaxLiftG = cfg.Bind<float>("Flight", "MaxLiftG", 2f, "Lift at full collective as a multiple of gravity. 2.0 means hover at ~50% collective.");
			CollectiveRate = cfg.Bind<float>("Flight", "CollectiveRate", 0.45f, "How fast holding W/S moves the collective (fraction of full range per second).");
			MaxPitchRollRate = cfg.Bind<float>("Flight", "MaxPitchRollRate", 90f, "Cap on pitch/roll rotation speed (deg/s).");
			YawRate = cfg.Bind<float>("Flight", "YawRate", 65f, "Yaw speed with a pedal fully held (deg/s).");
			ControlResponse = cfg.Bind<float>("Flight", "ControlResponse", 6f, "How snappily the airframe reaches the commanded rotation rate. Higher = twitchier.");
			MouseSmoothing = cfg.Bind<float>("Flight", "MouseSmoothing", 0.08f, "Seconds of smoothing on mouse cyclic input.");
			AutoLevel = cfg.Bind<float>("Flight", "AutoLevel", 0f, "Self-levelling tendency. 0 = none (Arma-like, holds whatever attitude you set). Try 0.3 for an easier ride.");
			Weathervane = cfg.Bind<float>("Flight", "Weathervane", 0.5f, "How strongly the tail swings the nose into the direction of travel at speed.");
			SpinUpSeconds = cfg.Bind<float>("Flight", "SpinUpSeconds", 3f, "Rotor spin up/down time when you board/leave.");
			ForwardDrag = cfg.Bind<float>("Flight", "ForwardDrag", 0.003f, "Quadratic drag along the nose. Lower = higher top speed.");
			SideDrag = cfg.Bind<float>("Flight", "SideDrag", 0.02f, "Quadratic drag sideways.");
			VerticalDrag = cfg.Bind<float>("Flight", "VerticalDrag", 0.04f, "Quadratic drag up/down.");
			LinearDrag = cfg.Bind<float>("Flight", "LinearDrag", 0.15f, "Low-speed drag in all directions (stops endless drifting).");
			Mass = cfg.Bind<float>("Flight", "Mass", 600f, "Rigidbody mass. Mostly affects how it shoves things it bumps into.");
			CenterOfMassHeight = cfg.Bind<float>("Flight", "CenterOfMassHeight", 1.4f, "Height (m, before Scale) of the point the choppa pivots around. Higher = swings like it hangs from the rotor; lower = tips like a bottom-heavy toy.");
			CollectiveSpringBack = cfg.Bind<bool>("Flight", "CollectiveSpringBack", true, "Release W/S and the collective returns to hover (or to idle when sitting on the ground). Off = it stays where you leave it.");
			CollectiveReturnRate = cfg.Bind<float>("Flight", "CollectiveReturnRate", 1f, "How fast the collective springs back when released (fraction of full range per second).");
			HoverTiltCompensation = cfg.Bind<bool>("Flight", "HoverTiltCompensation", true, "Spring-back point adds a bit of lift when tilted so forward flight roughly holds altitude.");
			BreakApart = cfg.Bind<bool>("Crashing", "BreakApart", true, "Hard impacts smash the choppa into pieces.");
			CrashDeltaV = cfg.Bind<float>("Crashing", "CrashSpeed", 10f, "Sudden speed change (m/s in one physics step) that counts as a crash. Higher = sturdier.");
			CrashBlast = cfg.Bind<float>("Crashing", "CrashBlast", 8f, "How hard the pieces fly apart.");
			DebrisSeconds = cfg.Bind<float>("Crashing", "DebrisSeconds", 30f, "How long wreckage lies around. 0 = forever.");
			CrashStunRadius = cfg.Bind<float>("Crashing", "StunRadius", 6f, "Your character gets knocked down if within this distance of a crash (pilot always is).");
			HeliScale = cfg.Bind<float>("Model", "Scale", 1f, "Overall size of the choppa.");
			SeatHeightOffset = cfg.Bind<float>("Model", "SeatHeightOffset", 0f, "Raise/lower where you sit (metres, before Scale).");
			SeatForwardOffset = cfg.Bind<float>("Model", "SeatForwardOffset", 0f, "Move where you sit forward/back (metres, before Scale).");
			EnterDistance = cfg.Bind<float>("Model", "EnterDistance", 5f, "How close you need to be to the nearest part of the choppa to board.");
			ChaseDistance = cfg.Bind<float>("Model", "ChaseCameraDistance", 12f, "Chase camera distance behind the choppa.");
			ChaseHeight = cfg.Bind<float>("Model", "ChaseCameraHeight", 3.5f, "Chase camera height above the choppa.");
			CockpitEyeHeight = cfg.Bind<float>("Model", "CockpitEyeHeightOffset", 0f, "Nudge the cockpit camera up/down.");
			SitWhileFlying = cfg.Bind<bool>("Model", "SitWhileFlying", true, "Ask the game to put your character in its sitting pose while flying.");
			ChoppaLayer = cfg.Bind<int>("Model", "PhysicsLayer", -1, "Unity layer for the choppa's colliders. -1 = auto-detect one that collides with the ground (see LogOutput.log).");
			AudioVolume = cfg.Bind<float>("Audio", "Volume", 0.8f, "Choppa sound volume (rotor, motor, bonks). 0 = silent.");
			AudioMaxDistance = cfg.Bind<float>("Audio", "MaxHearingDistance", 250f, "How far away you can hear a choppa (metres).");
			LogbookEnabled = cfg.Bind<bool>("Pilot Logbook", "Enabled", true, "Send a few anonymous flight stats (spawns, boardings, flight time/height/speed) so the author can see how the choppa gets used. No names, Steam IDs or locations. Set to false to turn it off completely.");
			LogbookInstallId = cfg.Bind<string>("Pilot Logbook", "AnonymousId", "", "Random id generated on first use so your flights can be told apart from other people's. Not linked to you. Delete it to get a new one.");
			NetEnabled = cfg.Bind<bool>("Networking", "Enabled", true, "Share choppas with other players. Everyone in the lobby (host included) needs the mod; a host without it may kick you when you join.");
			NetSendRate = cfg.Bind<float>("Networking", "SendRate", 20f, "Position updates per second sent for a choppa you're flying.");
			NetInterpDelay = cfg.Bind<float>("Networking", "InterpolationDelay", 0.15f, "Seconds other players' choppas are shown in the past so their motion stays smooth. Raise if they stutter.");
			ShowHud = cfg.Bind<bool>("Debug", "ShowHud", true, "Show the flight HUD while flying.");
			VerboseLogging = cfg.Bind<bool>("Debug", "VerboseLogging", false, "Log extra detail to LogOutput.log and show a network status line on screen.");
		}
	}
	internal static class ChoppaCrash
	{
		public static void Break(Helicopter heli, int seed)
		{
			//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_0014: Unknown result type (might be due to invalid IL or missing references)
			State state = Random.state;
			Random.InitState(seed);
			try
			{
				BreakSeeded(heli);
			}
			finally
			{
				Random.state = state;
			}
		}

		private static void BreakSeeded(Helicopter heli)
		{
			//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_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_003a: 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_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: 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_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: 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_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: 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_0252: 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_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: 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_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			Transform val = ((Component)heli).transform.Find("Model");
			Vector3 impactVelocity = heli.ImpactVelocity;
			heli.Body.isKinematic = true;
			Vector3 val2 = ((Component)heli).transform.TransformPoint(heli.Body.centerOfMass);
			float value = ChoppaConfig.HeliScale.Value;
			float value2 = ChoppaConfig.DebrisSeconds.Value;
			ChoppaAudio.PlayCrash(val2);
			List<Transform> list = new List<Transform>();
			if ((Object)(object)heli.MainRotor != (Object)null)
			{
				list.Add(heli.MainRotor);
			}
			if ((Object)(object)heli.TailRotor != (Object)null)
			{
				list.Add(heli.TailRotor);
			}
			if ((Object)(object)val != (Object)null)
			{
				foreach (MeshRenderer componentsInChild in ((Component)val).GetComponentsInChildren<MeshRenderer>(true))
				{
					Transform transform = ((Component)componentsInChild).transform;
					if ((!((Object)(object)heli.MainRotor != (Object)null) || !transform.IsChildOf(heli.MainRotor)) && (!((Object)(object)heli.TailRotor != (Object)null) || !transform.IsChildOf(heli.TailRotor)))
					{
						list.Add(transform);
					}
				}
			}
			foreach (Transform item in list)
			{
				item.SetParent((Transform)null, true);
				foreach (MeshRenderer componentsInChild2 in ((Component)item).GetComponentsInChildren<MeshRenderer>(true))
				{
					if ((Object)(object)((Component)componentsInChild2).GetComponent<Collider>() == (Object)null)
					{
						((Component)componentsInChild2).gameObject.AddComponent<BoxCollider>();
					}
				}
				Rigidbody val3 = ((Component)item).gameObject.AddComponent<Rigidbody>();
				bool flag = (Object)(object)item == (Object)(object)heli.MainRotor || (Object)(object)item == (Object)(object)heli.TailRotor;
				val3.mass = (flag ? 40f : 15f);
				val3.interpolation = (RigidbodyInterpolation)1;
				val3.maxAngularVelocity = 60f;
				val3.angularDamping = 0.3f;
				Vector3 val4 = item.position - val2;
				val4 = ((((Vector3)(ref val4)).sqrMagnitude < 0.01f) ? Random.onUnitSphere : ((Vector3)(ref val4)).normalized);
				float value3 = ChoppaConfig.CrashBlast.Value;
				val3.linearVelocity = impactVelocity * 0.5f + val4 * Random.Range(0.4f, 1f) * value3 * value + Vector3.up * Random.Range(0.3f, 0.8f) * value3 * value;
				val3.angularVelocity = Random.insideUnitSphere * 12f;
				ChoppaPhysics.CollideWithEverything(((Component)item).gameObject);
				ChoppaBonker.Add(((Component)item).gameObject, flag ? 0.8f : Random.Range(0.1f, 0.6f), 1.2f);
				if ((Object)(object)item == (Object)(object)heli.MainRotor)
				{
					val3.linearVelocity += ((Component)heli).transform.up * (value3 * 0.8f * value);
					val3.angularVelocity = ((Component)heli).transform.up * (heli.RotorSpin * 40f + 5f);
				}
				if (value2 > 0f)
				{
					Object.Destroy((Object)(object)((Component)item).gameObject, value2 + Random.Range(0f, 3f));
				}
			}
			Object.Destroy((Object)(object)((Component)heli).gameObject);
		}
	}
	internal static class ChoppaInput
	{
		private static bool rewiredBroken;

		private static bool unityBroken;

		private static readonly Dictionary<KeyCode, bool> prev = new Dictionary<KeyCode, bool>();

		private static readonly Dictionary<KeyCode, bool> cur = new Dictionary<KeyCode, bool>();

		public static string ActiveBackend { get; private set; } = "none";

		public static void Tick()
		{
			//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_0024: 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_003a: 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)
			foreach (KeyCode item in new List<KeyCode>(cur.Keys))
			{
				prev[item] = cur[item];
				cur[item] = RawKey(item);
			}
		}

		public static bool Held(KeyCode k)
		{
			//IL_0000: 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_003e: 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_0018: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			if ((int)k == 0)
			{
				return false;
			}
			if (!cur.ContainsKey(k))
			{
				cur[k] = RawKey(k);
				prev[k] = cur[k];
			}
			return cur[k];
		}

		public static bool Pressed(KeyCode k)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (Held(k))
			{
				return !prev[k];
			}
			return false;
		}

		public static float Axis(KeyCode negative, KeyCode positive)
		{
			//IL_0000: 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)
			return (Held(positive) ? 1f : 0f) - (Held(negative) ? 1f : 0f);
		}

		public static Vector2 MouseDelta()
		{
			//IL_0076: 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_0031: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			if (UseRewired())
			{
				try
				{
					if (ReInput.isReady)
					{
						Mouse mouse = ReInput.controllers.Mouse;
						ActiveBackend = "Rewired";
						return new Vector2(((ControllerWithAxes)mouse).GetAxisRaw(0), ((ControllerWithAxes)mouse).GetAxisRaw(1));
					}
				}
				catch (Exception e)
				{
					MarkRewiredBroken(e);
				}
			}
			if (UseUnity())
			{
				try
				{
					ActiveBackend = "Unity";
					return new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
				}
				catch (Exception e2)
				{
					MarkUnityBroken(e2);
				}
			}
			return Vector2.zero;
		}

		private static bool RawKey(KeyCode k)
		{
			//IL_003d: 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)
			if (UseRewired())
			{
				try
				{
					if (ReInput.isReady && ReInput.controllers.keyboardEnabled)
					{
						return ReInput.controllers.Keyboard.GetKey(k);
					}
				}
				catch (Exception e)
				{
					MarkRewiredBroken(e);
				}
			}
			if (UseUnity())
			{
				try
				{
					return Input.GetKey(k);
				}
				catch (Exception e2)
				{
					MarkUnityBroken(e2);
				}
			}
			return false;
		}

		private static bool UseRewired()
		{
			if (!rewiredBroken)
			{
				return ChoppaConfig.Backend.Value != InputBackend.Unity;
			}
			return false;
		}

		private static bool UseUnity()
		{
			if (!unityBroken)
			{
				return ChoppaConfig.Backend.Value != InputBackend.Rewired;
			}
			return false;
		}

		private static void MarkRewiredBroken(Exception e)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			rewiredBroken = true;
			ManualLogSource l = Plugin.L;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(51, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Rewired input failed, falling back to Unity Input: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(e.Message);
			}
			l.LogWarning(val);
		}

		private static void MarkUnityBroken(Exception e)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			unityBroken = true;
			ManualLogSource l = Plugin.L;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(27, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Unity legacy Input failed: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(e.Message);
			}
			l.LogWarning(val);
		}
	}
	internal static class ChoppaLogbook
	{
		public struct Flight
		{
			public float Seconds;

			public float Distance;

			public float MaxAltitude;

			public float TopSpeedKmh;

			public float EndSpeedKmh;

			public float UpsideDownSeconds;

			public float CockpitPercent;

			public string How;

			public int Riders;

			public int Rolls;

			public int Loops;
		}

		private const string Endpoint = "https://us.i.posthog.com/batch/";

		private const string ProjectKey = "phc_ubbcXrLXwRGBKUnLChUj6uzMQpCMNrcmjLALTKQMivbg";

		private static readonly HttpClient http = new HttpClient
		{
			Timeout = TimeSpan.FromSeconds(10.0)
		};

		private static readonly List<Dictionary<string, object>> queue = new List<Dictionary<string, object>>();

		private static float nextFlush;

		private static bool sending;

		private static bool On => ChoppaConfig.LogbookEnabled.Value;

		public static void Spawned()
		{
			Log("choppa_spawned", null);
		}

		public static void Boarded(bool pilot)
		{
			Log("choppa_boarded", new Dictionary<string, object> { ["seat"] = (pilot ? "pilot" : "passenger") });
		}

		public static void FlightEnded(Flight f)
		{
			Log("flight_ended", new Dictionary<string, object>
			{
				["duration_s"] = Mathf.Round(f.Seconds),
				["distance_m"] = Mathf.Round(f.Distance),
				["max_altitude_m"] = Mathf.Round(f.MaxAltitude),
				["top_speed_kmh"] = Mathf.Round(f.TopSpeedKmh),
				["end_speed_kmh"] = Mathf.Round(f.EndSpeedKmh),
				["how"] = f.How,
				["riders"] = f.Riders,
				["rolls"] = f.Rolls,
				["loops"] = f.Loops,
				["upside_down_s"] = Mathf.Round(f.UpsideDownSeconds),
				["cockpit_view_pct"] = Mathf.Round(f.CockpitPercent)
			});
		}

		public static void RideEnded(float seconds, string how)
		{
			Log("ride_ended", new Dictionary<string, object>
			{
				["duration_s"] = Mathf.Round(seconds),
				["how"] = how
			});
		}

		public static void FlippedUpright(bool seated)
		{
			Log("flipped_upright", new Dictionary<string, object> { ["from"] = (seated ? "inside" : "outside") });
		}

		public static void JumpedOut(bool pilot, float height, float speedKmh)
		{
			Log("jumped_out", new Dictionary<string, object>
			{
				["seat"] = (pilot ? "pilot" : "passenger"),
				["height_m"] = Mathf.Round(height),
				["speed_kmh"] = Mathf.Round(speedKmh)
			});
		}

		private static void Log(string evt, Dictionary<string, object> props)
		{
			if (!On)
			{
				return;
			}
			if (props == null)
			{
				props = new Dictionary<string, object>();
			}
			props["distinct_id"] = InstallId();
			props["mod_version"] = "1.0.2";
			props["$process_person_profile"] = false;
			props["$geoip_disable"] = true;
			props["$ip"] = "";
			lock (queue)
			{
				queue.Add(new Dictionary<string, object>
				{
					["event"] = evt,
					["properties"] = props,
					["timestamp"] = DateTime.UtcNow.ToString("o")
				});
				if (queue.Count > 200)
				{
					queue.RemoveAt(0);
				}
			}
			Plugin.Verbose("Logbook: " + evt);
		}

		private static string InstallId()
		{
			string text = ChoppaConfig.LogbookInstallId.Value;
			if (string.IsNullOrEmpty(text))
			{
				text = Guid.NewGuid().ToString("N");
				ChoppaConfig.LogbookInstallId.Value = text;
			}
			return text;
		}

		public static void Tick()
		{
			if (Time.unscaledTime < nextFlush)
			{
				return;
			}
			nextFlush = Time.unscaledTime + 30f;
			string json = TakeBatch();
			if (json == null || sending)
			{
				return;
			}
			sending = true;
			Task.Run(async delegate
			{
				try
				{
					await http.PostAsync("https://us.i.posthog.com/batch/", new StringContent(json, Encoding.UTF8, "application/json"));
				}
				catch
				{
				}
				finally
				{
					sending = false;
				}
			});
		}

		public static void FlushNow()
		{
			string text = TakeBatch();
			if (text == null)
			{
				return;
			}
			try
			{
				http.PostAsync("https://us.i.posthog.com/batch/", new StringContent(text, Encoding.UTF8, "application/json")).Wait(TimeSpan.FromSeconds(2.0));
			}
			catch
			{
			}
		}

		private static string TakeBatch()
		{
			lock (queue)
			{
				if (queue.Count == 0)
				{
					return null;
				}
				if (!On)
				{
					queue.Clear();
					return null;
				}
				string result = JsonSerializer.Serialize(new Dictionary<string, object>
				{
					["api_key"] = "phc_ubbcXrLXwRGBKUnLChUj6uzMQpCMNrcmjLALTKQMivbg",
					["batch"] = queue
				});
				queue.Clear();
				return result;
			}
		}
	}
	public class ChoppaManager : MonoBehaviour
	{
		private enum CamMode
		{
			Chase,
			Cockpit
		}

		private PlayerCharacter local;

		private float nextPlayerSearch;

		private readonly Dictionary<uint, Helicopter> helis = new Dictionary<uint, Helicopter>();

		private readonly Dictionary<uint, PlayerCharacter> players = new Dictionary<uint, PlayerCharacter>();

		private readonly Dictionary<uint, float> sendTimers = new Dictionary<uint, float>();

		private float nextPlayerScan;

		private int choppaLayer = -1;

		private bool seated;

		private Helicopter seatHeli;

		private int seatIndex;

		private uint pendingBoardId;

		private float pendingBoardUntil;

		private uint pendingSpawnId;

		private Rigidbody playerBody;

		private Transform playerRoot;

		private Collider[] playerColliders = Array.Empty<Collider>();

		private bool savedKinematic;

		private bool savedDetect;

		private bool savedBypassUpdate;

		private bool savedBypassFixed;

		private bool savedBypassLate;

		private RigidbodyInterpolation savedInterp;

		private Transform kernal;

		private Quaternion savedKernalLocalRot;

		private Camera cam;

		private Transform camParent;

		private Vector3 camLocalPos;

		private Quaternion camLocalRot;

		private Vector3 eyeOffset;

		private CamMode camMode;

		private Vector2 smoothedCyclic;

		private float lookYaw;

		private float lookPitch;

		private Vector3 chaseVel;

		private bool showHud;

		private string lastHint;

		private Helicopter spawnHeli;

		private float spawnY;

		private float spawnCheckAt = -1f;

		private float flightStart = -1f;

		private float flightMaxAlt;

		private float flightTopSpeed;

		private float flightDistance;

		private float groundedSince = -1f;

		private float flightUpsideDown;

		private float flightCockpitTime;

		private float flightRollAccum;

		private float flightPitchAccum;

		private float rideStart = -1f;

		private int flightRolls;

		private int flightLoops;

		private Vector3 flightLastPos;

		private float hintUntil;

		private uint Me => ChoppaNet.LocalNetId;

		public ChoppaManager(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Start()
		{
			showHud = ChoppaConfig.ShowHud.Value;
			Helicopter.Crashed += OnOwnCrash;
			ChoppaNet.ServerReceived = ChoppaServer.OnMessage;
			ChoppaNet.ClientReceived = OnClientMessage;
			ChoppaNet.ModeChanged = ClearWorld;
		}

		private void OnDestroy()
		{
			Helicopter.Crashed -= OnOwnCrash;
		}

		private void OnApplicationQuit()
		{
			ChoppaLogbook.FlushNow();
		}

		private void Update()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			try
			{
				Tick();
			}
			catch (Exception ex)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(22, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ChoppaManager.Update: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				l.LogError(val);
			}
		}

		private void Tick()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Invalid comparison between Unknown and I4
			//IL_007f: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			ChoppaInput.Tick();
			ChoppaNet.Tick();
			if (!FindLocalPlayer())
			{
				if (seated)
				{
					ForceUnseat("local player disappeared");
				}
				return;
			}
			ChoppaNet.LocalNetId = ((((NetworkBehaviour)local).netId == 0) ? 1u : ((NetworkBehaviour)local).netId);
			PruneDead();
			if (Time.unscaledTime >= nextPlayerScan)
			{
				ScanPlayers();
			}
			bool flag = !ChoppaConfig.RequireCursorLock.Value || (int)Cursor.lockState == 1;
			if (flag && ChoppaInput.Pressed(ChoppaConfig.HudKey.Value))
			{
				showHud = !showHud;
			}
			if (flag && ChoppaInput.Pressed(ChoppaConfig.SpawnKey.Value) && !seated)
			{
				RequestSpawn();
			}
			if (flag && ChoppaInput.Pressed(ChoppaConfig.ResetKey.Value))
			{
				ResetMine();
			}
			if (flag && ChoppaInput.Pressed(ChoppaConfig.EnterExitKey.Value))
			{
				if (seated)
				{
					Leave();
				}
				else
				{
					TryBoard();
				}
			}
			if (pendingBoardId != 0 && Time.time > pendingBoardUntil)
			{
				pendingBoardId = 0u;
				Hint("Couldn't board - the seat was taken or the host didn't answer.");
			}
			CheckSpawnSettled();
			foreach (Helicopter value in helis.Values)
			{
				if (!value.IsProxy && (!seated || !((Object)(object)seatHeli == (Object)(object)value) || seatIndex != 0))
				{
					value.CommandedRates = Vector3.zero;
				}
			}
			if (seated && seatIndex == 0 && !seatHeli.IsProxy)
			{
				FlyInput(flag);
				TrackFlight(seatHeli);
			}
			SendStates();
			ChoppaLogbook.Tick();
		}

		private void FixedUpdate()
		{
			if (seated)
			{
				PinPlayer();
			}
			PinRemotePassengers();
		}

		private void LateUpdate()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			try
			{
				PinRemotePassengers();
				if (seated)
				{
					PinPlayer();
					UpdateCamera();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ChoppaManager.LateUpdate: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				l.LogError(val);
			}
		}

		private bool FindLocalPlayer()
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			if ((Object)(object)local != (Object)null && Alive((Object)(object)local))
			{
				return true;
			}
			local = null;
			if (Time.unscaledTime < nextPlayerSearch)
			{
				return false;
			}
			nextPlayerSearch = Time.unscaledTime + 1f;
			bool flag = default(bool);
			foreach (PlayerCharacter item in Object.FindObjectsByType<PlayerCharacter>((FindObjectsSortMode)0))
			{
				if (!((Object)(object)item == (Object)null) && ((NetworkBehaviour)item).isLocalPlayer)
				{
					local = item;
					ManualLogSource l = Plugin.L;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(29, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Found local player '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)((Component)item).gameObject).name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' netId ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(((NetworkBehaviour)item).netId);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					l.LogInfo(val);
					return true;
				}
			}
			return false;
		}

		private void ScanPlayers()
		{
			nextPlayerScan = Time.unscaledTime + 1f;
			players.Clear();
			foreach (PlayerCharacter item in Object.FindObjectsByType<PlayerCharacter>((FindObjectsSortMode)0))
			{
				if ((Object)(object)item != (Object)null && ((NetworkBehaviour)item).netId != 0)
				{
					players[((NetworkBehaviour)item).netId] = item;
				}
			}
			if ((Object)(object)local != (Object)null)
			{
				players[Me] = local;
			}
			if (ChoppaNet.Mode == ChoppaNet.NetMode.Host)
			{
				ChoppaServer.Prune(ChoppaNet.ConnectedPlayers(), Me);
			}
			else if (ChoppaNet.Mode == ChoppaNet.NetMode.Offline)
			{
				ChoppaServer.Prune(new HashSet<uint> { Me }, Me);
			}
		}

		private PlayerCharacter Player(uint netId)
		{
			if (netId == 0)
			{
				return null;
			}
			if (players.TryGetValue(netId, out var value) && Alive((Object)(object)value))
			{
				return value;
			}
			return null;
		}

		private string NameOf(uint netId)
		{
			if (netId == Me)
			{
				return "you";
			}
			try
			{
				PlayerCharacter obj = Player(netId);
				object obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					PlayerNetworking playerNetworking = obj.playerNetworking;
					obj2 = ((playerNetworking != null) ? playerNetworking.username : null);
				}
				string text = (string)obj2;
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			catch
			{
			}
			return $"player {netId}";
		}

		private void OnClientMessage(Msg type, BinaryReader r)
		{
			//IL_003b: 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_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			switch (type)
			{
			case Msg.Spawn:
			{
				uint id = r.ReadUInt32();
				uint owner = r.ReadUInt32();
				OnSpawned(id, owner, r.ReadVector3(), r.ReadQuaternion());
				break;
			}
			case Msg.State:
			{
				if (helis.TryGetValue(r.ReadUInt32(), out var value4))
				{
					value4.ReadState(r);
				}
				break;
			}
			case Msg.Seats:
			{
				uint key3 = r.ReadUInt32();
				int num3 = r.ReadByte();
				uint[] array = new uint[3];
				for (int i = 0; i < num3; i++)
				{
					uint num4 = r.ReadUInt32();
					if (i < array.Length)
					{
						array[i] = num4;
					}
				}
				if (helis.TryGetValue(key3, out var value5))
				{
					OnSeats(value5, array);
				}
				break;
			}
			case Msg.Owner:
			{
				uint num = r.ReadUInt32();
				uint num2 = r.ReadUInt32();
				if (helis.TryGetValue(num, out var value3))
				{
					value3.Owner = num2;
					value3.SetProxy(num2 != Me);
					Plugin.Verbose($"Choppa {num:X8} now simulated by {NameOf(num2)}.");
				}
				break;
			}
			case Msg.Crash:
			{
				uint key2 = r.ReadUInt32();
				Vector3 impact = r.ReadVector3();
				int seed = r.ReadInt32();
				if (helis.TryGetValue(key2, out var value2))
				{
					HandleCrash(value2, impact, seed);
				}
				break;
			}
			case Msg.Despawn:
			{
				uint key = r.ReadUInt32();
				if (helis.TryGetValue(key, out var value))
				{
					if (seated && (Object)(object)seatHeli == (Object)(object)value)
					{
						ForceUnseat("choppa removed");
					}
					helis.Remove(key);
					if (Alive((Object)(object)value))
					{
						Object.Destroy((Object)(object)((Component)value).gameObject);
					}
				}
				break;
			}
			case Msg.Board:
			case Msg.Leave:
				break;
			}
		}

		private void OnSpawned(uint id, uint owner, Vector3 pos, Quaternion rot)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_0029: 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_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_00d0: 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)
			if (!helis.ContainsKey(id) && !((Object)(object)local == (Object)null))
			{
				if (choppaLayer < 0)
				{
					choppaLayer = PickLayer(GroundBelow(pos + Vector3.up * 2f, 10f, out var _));
				}
				Helicopter helicopter = Helicopter.Build(id, pos, rot, choppaLayer, ((Component)local).gameObject.scene);
				helicopter.Owner = owner;
				helicopter.SetProxy(owner != Me);
				helis[id] = helicopter;
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(24, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Choppa ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(id, "X8");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" spawned at ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(pos);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" by ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(NameOf(owner));
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(helicopter.IsProxy ? " (remote)" : "");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				l.LogInfo(val);
				if (id == pendingSpawnId)
				{
					pendingSpawnId = 0u;
					spawnHeli = helicopter;
					ChoppaLogbook.Spawned();
					spawnY = pos.y;
					spawnCheckAt = Time.time + 2f;
				}
			}
		}

		private void OnSeats(Helicopter h, uint[] occ)
		{
			uint[] occupants = h.Occupants;
			for (int i = 0; i < occ.Length; i++)
			{
				if (occupants[i] != occ[i])
				{
					if (occupants[i] != 0 && occupants[i] != Me)
					{
						IgnoreRemote(h, occupants[i], ignore: false);
					}
					if (occ[i] != 0 && occ[i] != Me)
					{
						IgnoreRemote(h, occ[i], ignore: true);
					}
				}
			}
			h.Occupants = occ;
			if (!h.IsProxy)
			{
				h.EngineOn = occ[0] != 0;
			}
			int num = Array.IndexOf(occ, Me);
			if (seated && (Object)(object)seatHeli == (Object)(object)h && num != seatIndex)
			{
				if (num < 0)
				{
					ForceUnseat("host removed us from the seat");
				}
				else
				{
					seatIndex = num;
				}
			}
			else if (!seated && num >= 0 && pendingBoardId == h.Id)
			{
				pendingBoardId = 0u;
				Seat(h, num);
			}
		}

		private void IgnoreRemote(Helicopter h, uint netId, bool ignore)
		{
			PlayerCharacter val = Player(netId);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			foreach (Collider componentsInChild in ((Component)h).GetComponentsInChildren<Collider>(true))
			{
				foreach (Collider componentsInChild2 in ((Component)val).GetComponentsInChildren<Collider>(true))
				{
					if ((Object)(object)componentsInChild != (Object)null && (Object)(object)componentsInChild2 != (Object)null)
					{
						Physics.IgnoreCollision(componentsInChild, componentsInChild2, ignore);
					}
				}
			}
		}

		private void PinRemotePassengers()
		{
			//IL_006b: 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)
			foreach (Helicopter value in helis.Values)
			{
				if ((Object)(object)value == (Object)null || value.Broken)
				{
					continue;
				}
				for (int i = 0; i < 3; i++)
				{
					uint num = value.Occupants[i];
					if (num != 0 && num != Me)
					{
						PlayerCharacter val = Player(num);
						if (!((Object)(object)val == (Object)null))
						{
							Transform val2 = value.Seats[i];
							((Component)val).transform.SetPositionAndRotation(val2.position, val2.rotation);
						}
					}
				}
			}
		}

		private void SendStates()
		{
			//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)
			ChoppaNet.NetMode mode = ChoppaNet.Mode;
			bool flag = (uint)(mode - 2) <= 1u;
			if (!flag || !ChoppaNet.Ready)
			{
				return;
			}
			foreach (Helicopter value2 in helis.Values)
			{
				if (value2.IsProxy || value2.Broken || value2.Owner != Me)
				{
					continue;
				}
				int num;
				if (!value2.Occupants.Any((uint o) => o != 0))
				{
					Vector3 linearVelocity = value2.Body.linearVelocity;
					num = ((((Vector3)(ref linearVelocity)).sqrMagnitude > 0.01f) ? 1 : 0);
				}
				else
				{
					num = 1;
				}
				bool flag2 = (byte)num != 0;
				float num2 = 1f / Mathf.Max(1f, flag2 ? ChoppaConfig.NetSendRate.Value : 2f);
				sendTimers.TryGetValue(value2.Id, out var value);
				value -= Time.deltaTime;
				if (value <= 0f)
				{
					value += num2;
					if (value < 0f)
					{
						value = num2;
					}
					ChoppaNet.ToServer(ChoppaNet.Write(Msg.State, value2.WriteState), reliable: false);
				}
				sendTimers[value2.Id] = value;
			}
		}

		private void PruneDead()
		{
			List<uint> list = null;
			foreach (KeyValuePair<uint, Helicopter> heli in helis)
			{
				if (!Alive((Object)(object)heli.Value))
				{
					(list ?? (list = new List<uint>())).Add(heli.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (uint item in list)
			{
				if (seated && (Object)(object)seatHeli != (Object)null && !Alive((Object)(object)seatHeli))
				{
					ForceUnseat("choppa destroyed");
				}
				helis.Remove(item);
				sendTimers.Remove(item);
			}
		}

		private void ClearWorld()
		{
			if (seated)
			{
				ForceUnseat("network session changed");
			}
			foreach (Helicopter value in helis.Values)
			{
				if (Alive((Object)(object)value))
				{
					Object.Destroy((Object)(object)((Component)value).gameObject);
				}
			}
			helis.Clear();
			sendTimers.Clear();
			pendingBoardId = (pendingSpawnId = 0u);
			ChoppaServer.Reset();
		}

		private void RequestSpawn()
		{
			//IL_0026: 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_0035: 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_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_006d: 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_0077: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if (!ChoppaNet.Ready)
			{
				Hint("Waiting for the host's Big Choppa to answer (does the host have the mod?).");
				return;
			}
			Transform transform = ((Component)local).transform;
			Vector3 val = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
			Vector3 val2 = ((Vector3)(ref val)).normalized;
			if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
			{
				val2 = Vector3.forward;
			}
			float value = ChoppaConfig.HeliScale.Value;
			Vector3 pos = transform.position + val2 * (6f * value);
			Vector3 point;
			Collider val3 = GroundBelow(pos + Vector3.up * 30f, 80f, out point);
			if ((Object)(object)val3 != (Object)null)
			{
				pos = point + Vector3.up * 0.15f;
			}
			if (choppaLayer < 0)
			{
				choppaLayer = PickLayer(val3);
			}
			Quaternion rot = Quaternion.LookRotation(Vector3.Cross(Vector3.up, val2), Vector3.up);
			foreach (Helicopter value2 in helis.Values)
			{
				if (value2.Owner == Me && value2.Occupants.All((uint o) => o == 0))
				{
					uint oldId = value2.Id;
					ChoppaNet.ToServer(ChoppaNet.Write(Msg.Despawn, delegate(BinaryWriter w)
					{
						w.Write(oldId);
					}), reliable: true);
				}
			}
			uint id;
			do
			{
				id = (uint)(Random.Range(1, int.MaxValue) ^ (Random.Range(0, 2) << 31));
			}
			while (id == 0 || helis.ContainsKey(id));
			pendingSpawnId = id;
			ChoppaNet.ToServer(ChoppaNet.Write(Msg.Spawn, delegate(BinaryWriter w)
			{
				//IL_000e: 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)
				w.Write(id);
				w.Write(pos);
				w.Write(rot);
			}), reliable: true);
		}

		private void CheckSpawnSettled()
		{
			//IL_0053: 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: Expected O, but got Unknown
			if (spawnCheckAt < 0f || Time.time < spawnCheckAt)
			{
				return;
			}
			spawnCheckAt = -1f;
			if ((Object)(object)spawnHeli == (Object)null || !Alive((Object)(object)spawnHeli))
			{
				return;
			}
			float num = spawnY - ((Component)spawnHeli).transform.position.y;
			if (num > 1f)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(73, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Choppa fell ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(num, "0.0");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("m in 2s after spawning - still not colliding with the ground.");
				}
				l.LogWarning(val);
			}
			else
			{
				Plugin.Verbose($"Choppa settled (moved {num:0.00}m vertically). Grounded={spawnHeli.Grounded}");
			}
		}

		private void ResetMine()
		{
			Helicopter helicopter = null;
			if (seated && !seatHeli.IsProxy)
			{
				helicopter = seatHeli;
			}
			else
			{
				float num = ChoppaConfig.EnterDistance.Value * ChoppaConfig.HeliScale.Value * 3f;
				foreach (Helicopter value in helis.Values)
				{
					if (!value.IsProxy)
					{
						float num2 = DistanceTo(value);
						if (num2 < num)
						{
							num = num2;
							helicopter = value;
						}
					}
				}
			}
			if ((Object)(object)helicopter != (Object)null)
			{
				ChoppaLogbook.FlippedUpright(seated);
				helicopter.ResetUpright();
			}
			else
			{
				Hint("Get in or next to a choppa you're flying to flip it upright.");
			}
		}

		private Collider GroundBelow(Vector3 origin, float distance, out Vector3 point)
		{
			//IL_0001: 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_0010: 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_002b: 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)
			point = default(Vector3);
			Collider result = null;
			float num = float.MaxValue;
			foreach (RaycastHit item in (Il2CppArrayBase<RaycastHit>)(object)Physics.RaycastAll(origin, Vector3.down, distance, -1, (QueryTriggerInteraction)1))
			{
				RaycastHit current = item;
				Collider collider = ((RaycastHit)(ref current)).collider;
				if (!((Object)(object)collider == (Object)null) && !(((RaycastHit)(ref current)).distance >= num) && !((Component)collider).transform.IsChildOf(((Component)local).transform) && !((Object)(object)((Component)collider).GetComponentInParent<Helicopter>() != (Object)null))
				{
					result = collider;
					num = ((RaycastHit)(ref current)).distance;
					point = ((RaycastHit)(ref current)).point;
				}
			}
			return result;
		}

		private int PickLayer(Collider rayGround)
		{
			int value = ChoppaConfig.ChoppaLayer.Value;
			if (value >= 0 && value < 32)
			{
				return value;
			}
			int num = -1;
			try
			{
				PlayerGround ground = local.ground;
				Collider val = ((ground != null) ? ground.groundCollider : null);
				if ((Object)(object)val != (Object)null)
				{
					num = ((Component)val).gameObject.layer;
				}
			}
			catch (Exception ex)
			{
				Plugin.Verbose("PlayerGround lookup failed: " + ex.Message);
			}
			if (num < 0 && (Object)(object)rayGround != (Object)null)
			{
				num = ((Component)rayGround).gameObject.layer;
			}
			if (num < 0)
			{
				num = 0;
			}
			int[] array = new int[32];
			foreach (Rigidbody item in Object.FindObjectsByType<Rigidbody>((FindObjectsSortMode)0))
			{
				if (!((Object)(object)item == (Object)null) && !item.isKinematic && !((Object)(object)((Component)item).GetComponentInParent<PlayerCharacter>() != (Object)null) && !((Object)(object)((Component)item).GetComponentInParent<Helicopter>() != (Object)null))
				{
					int layer = ((Component)item).gameObject.layer;
					if (!Physics.GetIgnoreLayerCollision(layer, num))
					{
						array[layer]++;
					}
				}
			}
			int num2 = -1;
			for (int i = 0; i < 32; i++)
			{
				if (array[i] > 0 && (num2 < 0 || array[i] > array[num2]))
				{
					num2 = i;
				}
			}
			if (num2 >= 0)
			{
				return num2;
			}
			int layer2 = (((Object)(object)local.rb != (Object)null) ? ((Component)local.rb).gameObject : ((Component)local).gameObject).layer;
			if (!Physics.GetIgnoreLayerCollision(layer2, num))
			{
				return layer2;
			}
			for (int j = 0; j < 32; j++)
			{
				if (!Physics.GetIgnoreLayerCollision(j, num))
				{
					return j;
				}
			}
			return 0;
		}

		private float DistanceTo(Helicopter h)
		{
			//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_0011: 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_0039: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)local).transform.position;
			float num = Vector3.Distance(position, ((Component)h).transform.position);
			foreach (Collider componentsInChild in ((Component)h).GetComponentsInChildren<Collider>())
			{
				num = Mathf.Min(num, Vector3.Distance(position, componentsInChild.ClosestPoint(position)));
			}
			return num;
		}

		private Helicopter NearestBoardable(out float dist)
		{
			Helicopter result = null;
			dist = float.MaxValue;
			float num = ChoppaConfig.EnterDistance.Value * ChoppaConfig.HeliScale.Value;
			foreach (Helicopter value in helis.Values)
			{
				if (!((Object)(object)value == (Object)null) && !value.Broken)
				{
					float num2 = DistanceTo(value);
					if (num2 < dist)
					{
						dist = num2;
						result = value;
					}
				}
			}
			if (!(dist <= num))
			{
				return null;
			}
			return result;
		}

		private static int FreeSeat(Helicopter h)
		{
			for (int i = 0; i < 3; i++)
			{
				if (h.Occupants[i] == 0)
				{
					return i;
				}
			}
			return -1;
		}

		private void TryBoard()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (helis.Count == 0)
			{
				Hint($"No choppa yet - press {ChoppaConfig.SpawnKey.Value} to spawn one.");
				return;
			}
			float dist;
			Helicopter helicopter = NearestBoardable(out dist);
			if ((Object)(object)helicopter == (Object)null)
			{
				Hint($"Too far from a choppa ({dist:0.0}m, need {ChoppaConfig.EnterDistance.Value * ChoppaConfig.HeliScale.Value:0.0}m).");
				return;
			}
			int num = FreeSeat(helicopter);
			if (num < 0)
			{
				Hint("That choppa is full.");
				return;
			}
			pendingBoardId = helicopter.Id;
			pendingBoardUntil = Time.time + 3f;
			byte s = (byte)num;
			uint id = helicopter.Id;
			ChoppaNet.ToServer(ChoppaNet.Write(Msg.Board, delegate(BinaryWriter w)
			{
				w.Write(id);
				w.Write(s);
			}), reliable: true);
		}

		private void Seat(Helicopter h, int index)
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: 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_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: 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_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			seatHeli = h;
			seatIndex = index;
			playerBody = local.rb;
			playerRoot = (((Object)(object)playerBody != (Object)null) ? ((Component)playerBody).transform : ((Component)local).transform);
			savedBypassUpdate = local.bypassUpdate;
			savedBypassFixed = local.bypassFixedUpdate;
			savedBypassLate = local.bypassLateUpdate;
			local.bypassUpdate = true;
			local.bypassFixedUpdate = true;
			local.bypassLateUpdate = true;
			if ((Object)(object)playerBody != (Object)null)
			{
				savedKinematic = playerBody.isKinematic;
				savedDetect = playerBody.detectCollisions;
				savedInterp = playerBody.interpolation;
				playerBody.linearVelocity = Vector3.zero;
				playerBody.isKinematic = true;
				playerBody.detectCollisions = false;
				playerBody.interpolation = (RigidbodyInterpolation)0;
			}
			playerColliders = ((IEnumerable<Collider>)((Component)local).GetComponentsInChildren<Collider>(true)).ToArray();
			foreach (Collider componentsInChild in ((Component)h).GetComponentsInChildren<Collider>(true))
			{
				Collider[] array = playerColliders;
				foreach (Collider val in array)
				{
					Physics.IgnoreCollision(componentsInChild, val, true);
				}
			}
			if (ChoppaConfig.SitWhileFlying.Value)
			{
				SetSitting(sitting: true);
			}
			kernal = local.kernal;
			if ((Object)(object)kernal != (Object)null)
			{
				savedKernalLocalRot = kernal.localRotation;
			}
			cam = null;
			try
			{
				PlayerCameraMinder cameraMinder = local.cameraMinder;
				object obj;
				if (cameraMinder == null)
				{
					obj = null;
				}
				else
				{
					PlayerCameraReferences playerCameraReferences = cameraMinder.playerCameraReferences;
					obj = ((playerCameraReferences != null) ? playerCameraReferences.playerCamera : null);
				}
				cam = (Camera)obj;
			}
			catch (Exception ex)
			{
				Plugin.Verbose("cameraMinder lookup failed: " + ex.Message);
			}
			if ((Object)(object)cam == (Object)null)
			{
				cam = Camera.main;
			}
			if ((Object)(object)cam != (Object)null)
			{
				eyeOffset = playerRoot.InverseTransformPoint(((Component)cam).transform.position);
				camParent = ((Component)cam).transform.parent;
				camLocalPos = ((Component)cam).transform.localPosition;
				camLocalRot = ((Component)cam).transform.localRotation;
				((Component)cam).transform.SetParent((Transform)null, true);
			}
			else
			{
				Plugin.L.LogWarning((object)"No camera found to take over; flying with whatever the game does.");
			}
			seated = true;
			flightStart = -1f;
			rideStart = ((index == 0) ? (-1f) : Time.time);
			ChoppaLogbook.Boarded(index == 0);
			if (index == 0 && !h.IsProxy)
			{
				h.EngineOn = true;
				h.Collective = 0f;
			}
			smoothedCyclic = Vector2.zero;
			lookYaw = (lookPitch = 0f);
			PinPlayer();
			Plugin.L.LogInfo((object)((index == 0) ? "Boarded choppa as pilot. Engine starting." : $"Boarded choppa as passenger (seat {index})."));
		}

		private void Leave()
		{
			//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_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_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_0043: 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_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_0061: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			Helicopter helicopter = seatHeli;
			int num = seatIndex;
			Vector3 position = helicopter.Exits[num].position;
			Vector3 velocity = helicopter.Velocity;
			Vector3 val = Vector3.ProjectOnPlane(((Component)helicopter).transform.forward, Vector3.up);
			Quaternion rot = Quaternion.LookRotation(((Vector3)(ref val)).normalized + Vector3.forward * 0.0001f, Vector3.up);
			if (num == 0 && !helicopter.IsProxy)
			{
				helicopter.EngineOn = false;
				helicopter.CommandedRates = Vector3.zero;
			}
			float num2 = Altitude(helicopter);
			if (num2 > 1.5f)
			{
				ChoppaLogbook.JumpedOut(num == 0, num2, ((Vector3)(ref velocity)).magnitude * 3.6f);
			}
			if (num == 0)
			{
				EndFlight(helicopter, helicopter.Grounded ? "landed" : "bailed", ((Vector3)(ref velocity)).magnitude * 3.6f);
			}
			else
			{
				EndRide((num2 > 1.5f) ? "jumped out" : "got out");
			}
			uint id = helicopter.Id;
			ChoppaNet.ToServer(ChoppaNet.Write(Msg.Leave, delegate(BinaryWriter w)
			{
				w.Write(id);
			}), reliable: true);
			Restore(position, rot, velocity);
			Plugin.L.LogInfo((object)"Left choppa.");
		}

		private void ForceUnseat(string why)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_004d: 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_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)
			ManualLogSource l = Plugin.L;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(22, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Forced out of choppa: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(why);
			}
			l.LogWarning(val);
			try
			{
				if ((Object)(object)local != (Object)null && Alive((Object)(object)local))
				{
					Restore(playerRoot.position, Quaternion.Euler(0f, playerRoot.eulerAngles.y, 0f), Vector3.zero);
				}
				else
				{
					RestoreCamera();
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogError((object)ex);
			}
			seated = false;
			seatHeli = null;
		}

		private void Restore(Vector3 pos, Quaternion rot, Vector3 vel)
		{
			//IL_0020: 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_003b: 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_0076: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			seated = false;
			if (ChoppaConfig.SitWhileFlying.Value)
			{
				SetSitting(sitting: false);
			}
			playerRoot.SetPositionAndRotation(pos, rot);
			if ((Object)(object)playerBody != (Object)null)
			{
				playerBody.position = pos;
				playerBody.rotation = rot;
				playerBody.isKinematic = savedKinematic;
				playerBody.detectCollisions = savedDetect;
				playerBody.interpolation = savedInterp;
				if (!playerBody.isKinematic)
				{
					playerBody.linearVelocity = vel;
				}
			}
			if ((Object)(object)kernal != (Object)null && Alive((Object)(object)kernal))
			{
				kernal.localRotation = savedKernalLocalRot;
			}
			kernal = null;
			local.bypassUpdate = savedBypassUpdate;
			local.bypassFixedUpdate = savedBypassFixed;
			local.bypassLateUpdate = savedBypassLate;
			if ((Object)(object)seatHeli != (Object)null && Alive((Object)(object)seatHeli))
			{
				foreach (Collider componentsInChild in ((Component)seatHeli).GetComponentsInChildren<Collider>(true))
				{
					Collider[] array = playerColliders;
					foreach (Collider val in array)
					{
						if ((Object)(object)componentsInChild != (Object)null && (Object)(object)val != (Object)null)
						{
							Physics.IgnoreCollision(componentsInChild, val, false);
						}
					}
				}
			}
			seatHeli = null;
			RestoreCamera();
		}

		private void RestoreCamera()
		{
			//IL_003f: 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)
			if (!((Object)(object)cam == (Object)null) && Alive((Object)(object)cam))
			{
				((Component)cam).transform.SetParent(camParent, false);
				((Component)cam).transform.localPosition = camLocalPos;
				((Component)cam).transform.localRotation = camLocalRot;
				cam = null;
			}
		}

		private void SetSitting(bool sitting)
		{
			try
			{
				PlayerSitter sitter = local.sitter;
				if (sitter != null)
				{
					sitter.SetSittingLocal(sitting);
				}
			}
			catch (Exception ex)
			{
				Plugin.Verbose($"SetSittingLocal({sitting}) failed: {ex.Message}");
			}
			try
			{
				PlayerNetworking playerNetworking = local.playerNetworking;
				if (playerNetworking != null)
				{
					playerNetworking.CmdSetSitting(sitting);
				}
			}
			catch (Exception ex2)
			{
				Plugin.Verbose($"CmdSetSitting({sitting}) failed: {ex2.Message}");
			}
		}

		private void PinPlayer()
		{
			//IL_0044: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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)
			if (!((Object)(object)seatHeli == (Object)null) && Alive((Object)(object)seatHeli) && !((Object)(object)playerRoot == (Object)null))
			{
				Transform val = seatHeli.Seats[seatIndex];
				playerRoot.SetPositionAndRotation(val.position, val.rotation);
				if ((Object)(object)playerBody != (Object)null)
				{
					playerBody.position = val.position;
					playerBody.rotation = val.rotation;
				}
				if ((Object)(object)kernal != (Object)null)
				{
					kernal.rotation = val.rotation;
				}
			}
		}

		private void FlyInput(bool inputAllowed)
		{
			//IL_0021: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: 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_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: 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_0192: 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_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			Helicopter helicopter = seatHeli;
			float num = Mathf.Max(Time.deltaTime, 0.0001f);
			Vector2 val = (inputAllowed ? ChoppaInput.MouseDelta() : Vector2.zero);
			bool num2 = inputAllowed && ChoppaInput.Held(ChoppaConfig.FreeLookKey.Value);
			if (inputAllowed && ChoppaInput.Pressed(ChoppaConfig.CameraKey.Value))
			{
				camMode = ((camMode == CamMode.Chase) ? CamMode.Cockpit : CamMode.Chase);
			}
			float num3 = (inputAllowed ? ChoppaInput.Axis(ChoppaConfig.CollectiveDownKey.Value, ChoppaConfig.CollectiveUpKey.Value) : 0f);
			if (!ChoppaConfig.CollectiveSpringBack.Value)
			{
				helicopter.Collective = Mathf.Clamp01(helicopter.Collective + num3 * ChoppaConfig.CollectiveRate.Value * num);
			}
			else if (num3 != 0f)
			{
				helicopter.Collective = Mathf.MoveTowards(helicopter.Collective, (num3 > 0f) ? 1f : 0f, ChoppaConfig.CollectiveRate.Value * num);
			}
			else
			{
				float num4 = 0f;
				if (!helicopter.Grounded)
				{
					num4 = helicopter.HoverCollective;
					if (ChoppaConfig.HoverTiltCompensation.Value)
					{
						num4 /= Mathf.Max(0.75f, Vector3.Dot(((Component)helicopter).transform.up, Vector3.up));
					}
				}
				helicopter.Collective = Mathf.MoveTowards(helicopter.Collective, Mathf.Clamp01(num4), ChoppaConfig.CollectiveReturnRate.Value * num);
			}
			float num5 = (inputAllowed ? ChoppaInput.Axis(ChoppaConfig.PedalLeftKey.Value, ChoppaConfig.PedalRightKey.Value) : 0f);
			Vector2 zero = Vector2.zero;
			if (num2)
			{
				lookYaw = Mathf.Clamp(lookYaw + val.x * 2f, -160f, 160f);
				lookPitch = Mathf.Clamp(lookPitch - val.y * 2f, -70f, 70f);
			}
			else
			{
				float num6 = ChoppaConfig.MouseSensitivity.Value / num;
				float num7 = val.y * num6 * (ChoppaConfig.InvertPitch.Value ? (-1f) : 1f);
				float num8 = (0f - val.x) * num6 * (ChoppaConfig.InvertRoll.Value ? (-1f) : 1f);
				float value = ChoppaConfig.MaxPitchRollRate.Value;
				((Vector2)(ref zero))..ctor(Mathf.Clamp(num7, 0f - value, value), Mathf.Clamp(num8, 0f - value, value));
				float num9 = 1f - Mathf.Exp((0f - num) * 8f);
				lookYaw = Mathf.Lerp(lookYaw, 0f, num9);
				lookPitch = Mathf.Lerp(lookPitch, 0f, num9);
			}
			float value2 = ChoppaConfig.MouseSmoothing.Value;
			float num10 = ((value2 <= 0f) ? 1f : (1f - Mathf.Exp((0f - num) / value2)));
			smoothedCyclic = Vector2.Lerp(smoothedCyclic, zero, num10);
			helicopter.CommandedRates = new Vector3(smoothedCyclic.x, num5 * ChoppaConfig.YawRate.Value, smoothedCyclic.y);
		}

		private void UpdateCamera()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Invalid comparison between Unknown and I4
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: 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_0191: 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_01a0: 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_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: 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_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: 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_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_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: 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_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: 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_029f: 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_011e: 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_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: 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_00a3: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam == (Object)null || !Alive((Object)(object)cam) || (Object)(object)seatHeli == (Object)null || !Alive((Object)(object)seatHeli))
			{
				return;
			}
			Transform transform = ((Component)seatHeli).transform;
			bool num = seatIndex == 0 && !seatHeli.IsProxy;
			bool flag = !ChoppaConfig.RequireCursorLock.Value || (int)Cursor.lockState == 1;
			if (!num && flag)
			{
				if (ChoppaInput.Pressed(ChoppaConfig.CameraKey.Value))
				{
					camMode = ((camMode == CamMode.Chase) ? CamMode.Cockpit : CamMode.Chase);
				}
				Vector2 val = ChoppaInput.MouseDelta();
				lookYaw = Mathf.Clamp(lookYaw + val.x * 2f, -170f, 170f);
				lookPitch = Mathf.Clamp(lookPitch - val.y * 2f, -70f, 70f);
			}
			if (camMode == CamMode.Cockpit)
			{
				Vector3 val2 = seatHeli.Seats[seatIndex].TransformPoint(eyeOffset) + transform.up * ChoppaConfig.CockpitEyeHeight.Value;
				((Component)cam).transform.SetPositionAndRotation(val2, transform.rotation * Quaternion.Euler(lookPitch, lookYaw, 0f));
				return;
			}
			float value = ChoppaConfig.HeliScale.Value;
			Vector3 val3 = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
			Quaternion val4 = Quaternion.LookRotation(((Vector3)(ref val3)).normalized + Vector3.forward * 0.0001f);
			float y = ((Quaternion)(ref val4)).eulerAngles.y;
			Quaternion val5 = Quaternion.Euler(10f + lookPitch, y + lookYaw, 0f);
			Vector3 val6 = transform.position + Vector3.up * (2f * value);
			Vector3 val7 = val6 + val5 * new Vector3(0f, 0f, (0f - ChoppaConfig.ChaseDistance.Value) * value) + Vector3.up * (ChoppaConfig.ChaseHeight.Value * value - 2f * value);
			((Component)cam).transform.position = Vector3.SmoothDamp(((Component)cam).transform.position, val7, ref chaseVel, 0.12f);
			((Component)cam).transform.rotation = Quaternion.LookRotation(val6 - ((Component)cam).transform.position, Vector3.up);
		}

		private static float Altitude(Helicopter h)
		{
			//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_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_0025: 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)
			float num = -1f;
			foreach (RaycastHit item in (Il2CppArrayBase<RaycastHit>)(object)Physics.RaycastAll(((Component)h).transform.position + Vector3.up * 0.5f, Vector3.down, 2000f, -1, (QueryTriggerInteraction)1))
			{
				RaycastHit current = item;
				if (!((Object)(object)((RaycastHit)(ref current)).collider == (Object)null) && !((Component)((RaycastHit)(ref current)).collider).transform.IsChildOf(((Component)h).transform) && !((Object)(object)((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<PlayerCharacter>() != (Object)null) && (num < 0f || ((RaycastHit)(ref current)).distance < num))
				{
					num = ((RaycastHit)(ref current)).distance;
				}
			}
			if (!(num < 0f))
			{
				return Mathf.Max(0f, num - 0.5f);
			}
			return -1f;
		}

		private void TrackFlight(Helicopter h)
		{
			//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_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_0090: 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_024a: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: 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_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val2;
			if (!h.Grounded)
			{
				groundedSince = -1f;
				Vector3 position = ((Component)h).transform.position;
				if (flightStart < 0f)
				{
					flightStart = Time.time;
					flightMaxAlt = (flightTopSpeed = (flightDistance = 0f));
					flightUpsideDown = (flightCockpitTime = (flightRollAccum = (flightPitchAccum = 0f)));
					flightRolls = (flightLoops = 0);
					flightLastPos = position;
				}
				float deltaTime = Time.deltaTime;
				if (Vector3.Dot(((Component)h).transform.up, Vector3.up) < 0f)
				{
					flightUpsideDown += deltaTime;
				}
				if (camMode == CamMode.Cockpit)
				{
					flightCockpitTime += deltaTime;
				}
				Vector3 val = ((Component)h).transform.InverseTransformDirection(h.Body.angularVelocity) * (57.29578f * deltaTime);
				flightRollAccum += val.z;
				flightPitchAccum += val.x;
				while (Mathf.Abs(flightRollAccum) >= 360f)
				{
					flightRolls++;
					flightRollAccum -= Mathf.Sign(flightRollAccum) * 360f;
				}
				while (Mathf.Abs(flightPitchAccum) >= 360f)
				{
					flightLoops++;
					flightPitchAccum -= Mathf.Sign(flightPitchAccum) * 360f;
				}
				flightDistance += Vector3.Distance(position, flightLastPos);
				flightLastPos = position;
				flightMaxAlt = Mathf.Max(flightMaxAlt, Altitude(h));
				float num = flightTopSpeed;
				val2 = h.Body.linearVelocity;
				flightTopSpeed = Mathf.Max(num, ((Vector3)(ref val2)).magnitude * 3.6f);
			}
			else if (flightStart >= 0f)
			{
				if (groundedSince < 0f)
				{
					groundedSince = Time.time;
				}
				else if (Time.time - groundedSince > 2f)
				{
					val2 = h.Velocity;
					EndFlight(h, "landed", ((Vector3)(ref val2)).magnitude * 3.6f);
				}
			}
		}

		private void EndFlight(Helicopter h, string how, float endSpeedKmh)
		{
			if (flightStart < 0f)
			{
				return;
			}
			float num = Time.time - flightStart;
			flightStart = -1f;
			groundedSince = -1f;
			if (!(num < 1f))
			{
				ChoppaLogbook.FlightEnded(new ChoppaLogbook.Flight
				{
					Seconds = num,
					Distance = flightDistance,
					MaxAltitude = flightMaxAlt,
					TopSpeedKmh = flightTopSpeed,
					EndSpeedKmh = endSpeedKmh,
					How = how,
					Riders = h.Occupants.Count((uint o) => o != 0),
					Rolls = flightRolls,
					Loops = flightLoops,
					UpsideDownSeconds = flightUpsideDown,
					CockpitPercent = 100f * flightCockpitTime / num
				});
			}
		}

		private void EndRide(string how)
		{
			if (!(rideStart < 0f))
			{
				float seconds = Time.time - rideStart;
				rideStart = -1f;
				ChoppaLogbook.RideEnded(seconds, how);
			}
		}

		private void OnOwnCrash(Helicopter crashed, float deltaV)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_005f: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			int seed = Random.Range(int.MinValue, int.MaxValue);
			uint id = crashed.Id;
			Vector3 impact = crashed.ImpactVelocity;
			try
			{
				ChoppaNet.ToServer(ChoppaNet.Write(Msg.Crash, delegate(BinaryWriter w)
				{
					//IL_000e: Unknown result type (might be due to invalid IL or missing references)
					w.Write(id);
					w.Write(impact);
					w.Write(seed);
				}), reliable: true);
			}
			catch (Exception ex)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool)