Decompiled source of Professional FPV Drone Piloting v1.8.2

BepInEx/plugins/HeliAgilityCap.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("HeliAgilityCap")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("HeliAgilityCap")]
[assembly: AssemblyTitle("HeliAgilityCap")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace HeliAgilityCap
{
	[BepInPlugin("local.ravenfield.heliagilitycap", "Helicopter Agility Cap", "1.8.2")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static ConfigEntry<float> MaxAngularVelocity;

		internal static ConfigEntry<string> Mode;

		internal static ConfigEntry<string> Names;

		internal static ConfigEntry<string> RateMode;

		internal static ConfigEntry<string> RateNames;

		internal static ConfigEntry<string> RollRates;

		internal static ConfigEntry<string> PitchRates;

		internal static ConfigEntry<string> YawRates;

		internal static ConfigEntry<string> ThrustRpm;

		internal static ConfigEntry<string> ThrustRpmNames;

		internal static ConfigEntry<string> Vpitch;

		internal static ConfigEntry<string> Fmax;

		internal static ConfigEntry<string> RotorSpoolTime;

		internal static ConfigEntry<string> RotorForce;

		internal static ConfigEntry<string> VerticalMode;

		internal static ConfigEntry<string> AerodynamicLift;

		internal static ConfigEntry<string> GroundEffectAcceleration;

		internal static ConfigEntry<string> Drag;

		internal static readonly FloatMapCache VpitchMap = new FloatMapCache("Vpitch");

		internal static readonly FloatMapCache FmaxMap = new FloatMapCache("Fmax");

		internal static readonly FloatMapCache SpoolMap = new FloatMapCache("RotorSpoolTime");

		internal static readonly FloatMapCache RotorForceMap = new FloatMapCache("RotorForce");

		internal static readonly FloatMapCache LiftMap = new FloatMapCache("AerodynamicLift");

		internal static readonly FloatMapCache GeaMap = new FloatMapCache("GroundEffectAcceleration");

		internal static readonly FloatMapCache DragMap = new FloatMapCache("Drag");

		private void Awake()
		{
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			MaxAngularVelocity = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaxAngularVelocity", 10f, "直升机类载具角速度上限(rad/s)。原版=1.5(约 86°/s)    //给使用原版操控的载具用的");
			Mode = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Mode", "names", "生效范围:all=所有直升机;player=仅玩家驾驶的;names=载具名包含 Names 列表的。");
			Names = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Names", "UFO,FPV", "Mode=names 时生效,逗号分隔,不区分大小写。");
			RateMode = ((BaseUnityPlugin)this).Config.Bind<string>("General", "RateMode", "on", "穿越机式姿态控制模式:off=不处理(杆量);actual(或 on)=旋转改为\"杆量直接映射到目标角速度\"(Betaflight Actual 曲线),接管后此载具的 manouverability、m_AngularDrag和角速度 1.5 上限都不再起作用。");
			RateNames = ((BaseUnityPlugin)this).Config.Bind<string>("General", "RateNames", "FPV", "RateMode 对哪些载具生效:载具名包含列表中任一词即可,逗号分隔、不区分大小写。留空 = 对所有直升机生效。");
			RollRates = ((BaseUnityPlugin)this).Config.Bind<string>("General", "RollRates", "270,500,0.1", "翻滚轴 Actual 参数,格式:中心灵敏度(deg/s), 满杆速率(deg/s), expo(0~1)。");
			PitchRates = ((BaseUnityPlugin)this).Config.Bind<string>("General", "PitchRates", "270,500,0.1", "俯仰轴 Actual 参数,格式同上。");
			YawRates = ((BaseUnityPlugin)this).Config.Bind<string>("General", "YawRates", "270,490,0.0", "偏航轴 Actual 参数,格式同上。");
			ThrustRpm = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ThrustRpm", "on", "启用定距桨气动模型:off=不处理;on=杆量映射桨叶转速。");
			ThrustRpmNames = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ThrustRpmNames", "FPV", "定距桨气动模型对哪些载具生效:载具名包含列表中任一词即可,逗号分隔、不区分大小写。留空 = 对所有直升机生效。");
			Vpitch = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Vpitch", "FPV:80", "桨距速度(m/s,主要决定极速):轴向速度达到该值时推力归零。格式:名称:值,名称:值,...——只有列出的载具单独设置;未列出(或写 -1)= 用默认 80。如 \"FPV:13,Mi-8:54\"。");
			Fmax = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Fmax", "FPV:1.25", "下降缓冲上限(未单独设置时用 1.25 = 下降时最多 +25% 推力)。格式同上。");
			RotorSpoolTime = ((BaseUnityPlugin)this).Config.Bind<string>("General", "RotorSpoolTime", "FPV:0.05", "转速响应时间(秒;未单独设置时用 0.05 ≈ 打杆后 0.15 秒到 95%,0=瞬时)。格式同上。");
			RotorForce = ((BaseUnityPlugin)this).Config.Bind<string>("General", "RotorForce", "FPV:100", "旋翼满转静态推力(覆盖原版载具属性)(m/s²,悬停转速=√(9.81/该值),务必 > 9.81):只有列出的载具生效(值必须 >0),如 \"FPV:125,Mi-8:150\";未列出(或值 ≤0)= 用原版载具属性。");
			VerticalMode = ((BaseUnityPlugin)this).Config.Bind<string>("General", "VerticalMode", "", "垂直杆量重映射(仅玩家、且当前载具在新气动名单内时生效):留空(默认)=自动 full;off=不处理;clamp=负杆量按 0 计;full=整杆程映射为 0~1(杆到底=0)。填值即覆盖自动。");
			AerodynamicLift = ((BaseUnityPlugin)this).Config.Bind<string>("General", "AerodynamicLift", "FPV:0.01", "aerodynamicLift(覆盖原版载具属性)(前飞升力系数:沿机身 up 施加 前飞速度×该值)。只有列出的载具生效,如 \"FPV:0.05,Mi-8:0.01\"(值 0 = 该车取消前飞升力);未列出(或写 -1)= 所有载具都不动(用文件值)。");
			GroundEffectAcceleration = ((BaseUnityPlugin)this).Config.Bind<string>("General", "GroundEffectAcceleration", "FPV:0", "groundEffectAcceleration(覆盖原版载具属性)(地效上限加速度,离地越近推力越强)。只有列出的载具生效,如 \"FPV:0\"(值 0 = 关地效);未列出(或写 -1)= 所有载具都不动(用文件值)。");
			Drag = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Drag", "FPV:0.02", "线性空气阻力(覆盖原版载具属性)(线性空气阻力 1/s)。只有列出的载具生效,如 \"FPV:0.05,Mi-8:0.02\";未列出(或写 -1)= 所有载具都不动(用文件值)。");
			((BaseUnityPlugin)this).Config.Save();
			new Harmony("local.ravenfield.heliagilitycap").PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"Helicopter Agility Cap 1.8.2 已加载。");
			Log.LogInfo((object)("driverInput 反射: " + ((DriverInputAccess.Ref != null) ? "OK" : "失败(将使用兜底取值)")));
			Log.LogInfo((object)("RateMode 配置: \"" + RateMode.Value + "\" → " + (RateModeEnabled() ? "启用" : "未启用")));
			Log.LogInfo((object)("ThrustRpm 配置: \"" + ThrustRpm.Value + "\" → " + (ThrustRpmEnabled() ? "启用" : "未启用")));
			Log.LogInfo((object)("VerticalMode 配置: \"" + VerticalMode.Value + "\" → " + (string.IsNullOrWhiteSpace(VerticalMode.Value) ? "自动(full)" : VerticalMode.Value.Trim())));
		}

		internal static bool ShouldApply(Helicopter heli)
		{
			switch (Mode.Value.Trim().ToLowerInvariant())
			{
			case "all":
				return true;
			case "player":
				if (((Vehicle)heli).HasDriver())
				{
					return ((Vehicle)heli).HasPlayerDriver();
				}
				return false;
			case "names":
			{
				string text = ((Vehicle)heli).name ?? string.Empty;
				string[] array = Names.Value.Split(new char[1] { ',' });
				for (int i = 0; i < array.Length; i++)
				{
					string text2 = array[i].Trim();
					if (text2.Length > 0 && text.IndexOf(text2, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return true;
					}
				}
				return false;
			}
			default:
				return false;
			}
		}

		internal static bool RateModeEnabled()
		{
			string text = RateMode.Value.Trim().ToLowerInvariant();
			if (!(text == "actual"))
			{
				return text == "on";
			}
			return true;
		}

		internal static bool RateModeAppliesTo(Vehicle vehicle)
		{
			return MatchesVehicleNameList(((Object)(object)vehicle != (Object)null) ? vehicle.name : null, RateNames.Value);
		}

		internal static bool ThrustRpmEnabled()
		{
			string text = ThrustRpm.Value.Trim().ToLowerInvariant();
			if (!(text == "on"))
			{
				return text == "true";
			}
			return true;
		}

		internal static bool ThrustRpmAppliesTo(Vehicle vehicle)
		{
			return MatchesVehicleNameList(((Object)(object)vehicle != (Object)null) ? vehicle.name : null, ThrustRpmNames.Value);
		}

		internal static bool MatchesVehicleNameList(string vehicleName, string list)
		{
			if (string.IsNullOrWhiteSpace(list))
			{
				return true;
			}
			vehicleName = vehicleName ?? string.Empty;
			string[] array = list.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0 && vehicleName.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal sealed class FloatMapCache
	{
		private readonly string keyName;

		private string raw;

		private string[] names = new string[0];

		private float[] values = new float[0];

		internal FloatMapCache(string keyName)
		{
			this.keyName = keyName;
		}

		internal float Resolve(string rawText, string vehicleName, float fallback)
		{
			if (rawText != raw)
			{
				Rebuild(rawText);
			}
			if (!string.IsNullOrEmpty(vehicleName))
			{
				for (int i = 0; i < names.Length; i++)
				{
					if (vehicleName.IndexOf(names[i], StringComparison.OrdinalIgnoreCase) >= 0)
					{
						if (!(values[i] < 0f))
						{
							return values[i];
						}
						return fallback;
					}
				}
			}
			return fallback;
		}

		private void Rebuild(string text)
		{
			raw = text;
			List<string> list = new List<string>();
			List<float> list2 = new List<float>();
			if (!string.IsNullOrEmpty(text))
			{
				string[] array = text.Split(new char[1] { ',' });
				for (int i = 0; i < array.Length; i++)
				{
					string text2 = array[i].Trim();
					if (text2.Length == 0)
					{
						continue;
					}
					int num = text2.LastIndexOf(':');
					if (num > 0)
					{
						string text3 = text2.Substring(0, num).Trim();
						string s = text2.Substring(num + 1).Trim();
						if (text3.Length > 0 && float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
						{
							list.Add(text3);
							list2.Add(result);
							continue;
						}
					}
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)(keyName + ":配置格式无法解析,已忽略该项:" + text2));
					}
				}
			}
			names = list.ToArray();
			values = list2.ToArray();
		}
	}
	internal static class DriverInputAccess
	{
		internal static readonly FieldRef<Vehicle, Vector4> Ref = Create();

		private static FieldRef<Vehicle, Vector4> Create()
		{
			try
			{
				return AccessTools.FieldRefAccess<Vehicle, Vector4>("driverInput");
			}
			catch
			{
				return null;
			}
		}

		internal static Vector4 Get(Helicopter heli)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_004f: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (Ref != null)
			{
				try
				{
					return Ref.Invoke((Vehicle)(object)heli);
				}
				catch
				{
				}
			}
			try
			{
				return Clamp(((Vehicle)heli).Driver().controller.HelicopterInput()) * ((Vehicle)heli).engine.power;
			}
			catch
			{
				return Vector4.zero;
			}
		}

		private static Vector4 Clamp(Vector4 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			return new Vector4(Mathf.Clamp(v.x, -1f, 1f), Mathf.Clamp(v.y, -1f, 1f), Mathf.Clamp(v.z, -1f, 1f), Mathf.Clamp(v.w, -1f, 1f));
		}
	}
	[HarmonyPatch(typeof(Helicopter), "FixedUpdate")]
	internal static class HelicopterFixedUpdatePatch
	{
		private static void Postfix(Helicopter __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Vehicle)__instance).rigidbody == (Object)null) && (!Plugin.RateModeEnabled() || !Plugin.RateModeAppliesTo((Vehicle)(object)__instance)) && Plugin.ShouldApply(__instance))
			{
				((Vehicle)__instance).rigidbody.maxAngularVelocity = Plugin.MaxAngularVelocity.Value;
			}
		}
	}
	[HarmonyPatch(typeof(FpsActorController), "HelicopterInput")]
	internal static class HelicopterInputVerticalPatch
	{
		private static void Postfix(FpsActorController __instance, ref Vector4 __result)
		{
			if (!Plugin.ThrustRpmEnabled())
			{
				return;
			}
			Vehicle currentVehicle = GetCurrentVehicle(__instance);
			if ((Object)(object)currentVehicle == (Object)null || !Plugin.ThrustRpmAppliesTo(currentVehicle))
			{
				return;
			}
			string text = Plugin.VerticalMode.Value.Trim().ToLowerInvariant();
			if (!(text == "off"))
			{
				if (text == "clamp")
				{
					__result.y = Mathf.Clamp(__result.y, 0f, 1f);
					return;
				}
				float num = Mathf.Clamp(__result.y, -1f, 1f);
				__result.y = (num + 1f) * 0.5f;
			}
		}

		private static Vehicle GetCurrentVehicle(FpsActorController controller)
		{
			Actor val = (((Object)(object)controller == (Object)null) ? null : ((ActorController)controller).actor);
			if ((Object)(object)val == (Object)null || (Object)(object)val.seat == (Object)null)
			{
				return null;
			}
			return val.seat.vehicle;
		}
	}
	[HarmonyPatch(typeof(Helicopter), "FixedUpdate")]
	internal static class HelicopterFieldOverridePatch
	{
		private static readonly HashSet<int> LiftLogged = new HashSet<int>();

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

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

		private static void Prefix(Helicopter __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)((Vehicle)__instance).rigidbody == (Object)null)
			{
				return;
			}
			string name = ((Vehicle)__instance).name;
			float num = Plugin.LiftMap.Resolve(Plugin.AerodynamicLift.Value, name, -1f);
			if (num >= 0f)
			{
				float aerodynamicLift = __instance.aerodynamicLift;
				if (aerodynamicLift != num)
				{
					__instance.aerodynamicLift = num;
				}
				if (LiftLogged.Add(((Object)__instance).GetInstanceID()))
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("aerodynamicLift 已覆盖:" + (name ?? "?") + " = " + num + "(文件值 " + aerodynamicLift + ")"));
					}
				}
			}
			float num2 = Plugin.GeaMap.Resolve(Plugin.GroundEffectAcceleration.Value, name, -1f);
			if (num2 >= 0f)
			{
				float groundEffectAcceleration = __instance.groundEffectAcceleration;
				if (groundEffectAcceleration != num2)
				{
					__instance.groundEffectAcceleration = num2;
				}
				if (GeaLogged.Add(((Object)__instance).GetInstanceID()))
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)("groundEffectAcceleration 已覆盖:" + (name ?? "?") + " = " + num2 + "(文件值 " + groundEffectAcceleration + ")"));
					}
				}
			}
			float num3 = Plugin.DragMap.Resolve(Plugin.Drag.Value, name, -1f);
			if (!(num3 >= 0f))
			{
				return;
			}
			float drag = ((Vehicle)__instance).rigidbody.drag;
			if (drag != num3)
			{
				((Vehicle)__instance).rigidbody.drag = num3;
			}
			if (DragLogged.Add(((Object)__instance).GetInstanceID()))
			{
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)("Rigidbody.drag 已覆盖:" + (name ?? "?") + " = " + num3 + "(文件值 " + drag + ")"));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Helicopter), "FixedUpdate")]
	internal static class HelicopterRateModePatch
	{
		private static readonly HashSet<int> AppliedLogged = new HashSet<int>();

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

		private static void Postfix(Helicopter __instance)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.RateModeEnabled() || (Object)(object)__instance == (Object)null || (Object)(object)((Vehicle)__instance).rigidbody == (Object)null || ((Vehicle)__instance).dead || !((Vehicle)__instance).HasDriver())
			{
				return;
			}
			if (!Plugin.RateModeAppliesTo((Vehicle)(object)__instance))
			{
				if (NotMatchedLogged.Add(((Object)__instance).GetInstanceID()))
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("RateMode 未生效(名单不匹配):" + (((Vehicle)__instance).name ?? "?") + ",RateNames=" + Plugin.RateNames.Value));
					}
				}
				return;
			}
			Vector4 val = DriverInputAccess.Get(__instance);
			ParseRateTriple(Plugin.RollRates.Value, 150f, 400f, 0.6f, out var cs, out var mr, out var expo);
			ParseRateTriple(Plugin.PitchRates.Value, 120f, 350f, 0.5f, out var cs2, out var mr2, out var expo2);
			ParseRateTriple(Plugin.YawRates.Value, 100f, 300f, 0.3f, out var cs3, out var mr3, out var expo3);
			float num = (((Vehicle)__instance).burning ? __instance.controlWhenBurning : 1f);
			Vector3 val2 = new Vector3(ActualRate(val.w, cs2 * ((float)Math.PI / 180f), mr2 * ((float)Math.PI / 180f), expo2), ActualRate(val.x, cs3 * ((float)Math.PI / 180f), mr3 * ((float)Math.PI / 180f), expo3), 0f - ActualRate(val.z, cs * ((float)Math.PI / 180f), mr * ((float)Math.PI / 180f), expo)) * num;
			float num2 = 1f + ((Vehicle)__instance).rigidbody.angularDrag * Time.fixedDeltaTime;
			((Vehicle)__instance).rigidbody.maxAngularVelocity = Mathf.Max(((Vector3)(ref val2)).magnitude * num2 + 1f, 2f);
			__instance.manouverability = 0f;
			((Vehicle)__instance).rigidbody.angularVelocity = ((Component)__instance).transform.rotation * (val2 * num2);
			if (AppliedLogged.Add(((Object)__instance).GetInstanceID()))
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)("RateMode 已生效:" + (((Vehicle)__instance).name ?? "?") + "(Roll=" + Plugin.RollRates.Value + " Pitch=" + Plugin.PitchRates.Value + " Yaw=" + Plugin.YawRates.Value + ")"));
				}
			}
		}

		private static void ParseRateTriple(string text, float defaultCs, float defaultMr, float defaultExpo, out float cs, out float mr, out float expo)
		{
			cs = defaultCs;
			mr = defaultMr;
			expo = defaultExpo;
			if (string.IsNullOrWhiteSpace(text))
			{
				return;
			}
			string[] array = text.Split(new char[1] { ',' });
			if (array.Length >= 3)
			{
				if (!float.TryParse(array[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out cs))
				{
					cs = defaultCs;
				}
				if (!float.TryParse(array[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out mr))
				{
					mr = defaultMr;
				}
				if (!float.TryParse(array[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out expo))
				{
					expo = defaultExpo;
				}
			}
		}

		private static float ActualRate(float stick, float cs, float mr, float expo)
		{
			float num = Mathf.Abs(stick);
			if (num > 1f)
			{
				num = 1f;
			}
			float num2 = Mathf.Clamp01(expo);
			float num3 = num * (Mathf.Pow(num, 5f) * num2 + num * (1f - num2));
			float num4 = cs * num + (mr - cs) * num3;
			return Mathf.Sign(stick) * num4;
		}
	}
	[HarmonyPatch(typeof(Helicopter), "FixedUpdate")]
	internal static class HelicopterThrustRpmPatch
	{
		private sealed class OmegaState
		{
			public float omega;
		}

		private static readonly ConditionalWeakTable<Helicopter, OmegaState> OmegaStates = new ConditionalWeakTable<Helicopter, OmegaState>();

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

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

		private static void Postfix(Helicopter __instance)
		{
			//IL_00a1: 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_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: 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_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: 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_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0269: 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_026d: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ThrustRpmEnabled() || (Object)(object)__instance == (Object)null || (Object)(object)((Vehicle)__instance).rigidbody == (Object)null)
			{
				return;
			}
			if (!Plugin.ThrustRpmAppliesTo((Vehicle)(object)__instance))
			{
				if (NotMatchedLogged.Add(((Object)__instance).GetInstanceID()))
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("ThrustRpm 未生效(名单不匹配):" + (((Vehicle)__instance).name ?? "?") + ",ThrustRpmNames=" + Plugin.ThrustRpmNames.Value));
					}
				}
				return;
			}
			OmegaState orCreateValue = OmegaStates.GetOrCreateValue(__instance);
			if (((Vehicle)__instance).dead || !((Vehicle)__instance).HasDriver())
			{
				orCreateValue.omega = 0f;
				return;
			}
			float fixedDeltaTime = Time.fixedDeltaTime;
			float y = DriverInputAccess.Get(__instance).y;
			float num = Mathf.Clamp01(y);
			string name = ((Vehicle)__instance).name;
			float num2 = Plugin.VpitchMap.Resolve(Plugin.Vpitch.Value, name, 80f);
			float num3 = Plugin.FmaxMap.Resolve(Plugin.Fmax.Value, name, 1.25f);
			float num4 = Plugin.SpoolMap.Resolve(Plugin.RotorSpoolTime.Value, name, 0.05f);
			float rotorForce = __instance.rotorForce;
			float num5 = Plugin.RotorForceMap.Resolve(Plugin.RotorForce.Value, name, 0f);
			float num6 = ((num5 > 0f) ? num5 : rotorForce);
			if (num4 <= 0.0001f)
			{
				orCreateValue.omega = num;
			}
			else
			{
				orCreateValue.omega += (num - orCreateValue.omega) * Mathf.Min(1f, fixedDeltaTime / num4);
			}
			float omega = orCreateValue.omega;
			Vector3 val = ((Component)__instance).transform.up + ((Component)__instance).transform.forward * 0.05f;
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			Vector3 val2 = Vector3.Project(normalized, Vector3.up);
			val = normalized - 0.05f * val2;
			normalized = ((Vector3)(ref val)).normalized;
			float num7 = Vector3.Dot(((Vehicle)__instance).rigidbody.velocity, normalized);
			float num8 = Mathf.Clamp(1f - num7 / Mathf.Max(num2, 1f), 0f, num3);
			Vector3 val3 = ComputeGameThrust(__instance, y, normalized);
			float num9 = (((Vehicle)__instance).burning ? 0.3f : 1f);
			float num10 = ComputeGameGroundEffect(__instance, y, normalized);
			float num11 = num6 * omega * omega * num8 * num9 + num10;
			Vector3 val4 = normalized * num11;
			((Vehicle)__instance).rigidbody.AddForce(val4 - val3, (ForceMode)5);
			if (AppliedLogged.Add(((Object)__instance).GetInstanceID()))
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)("ThrustRpm 已生效:" + (((Vehicle)__instance).name ?? "?") + "(Vpitch=" + num2 + " Fmax=" + num3 + " Spool=" + num4 + " rotorForce=" + num6 + ((num5 > 0f) ? ("(配置;文件值 " + rotorForce + " 已忽略)") : "(文件)") + ")"));
				}
			}
		}

		private static Vector3 ComputeGameThrust(Helicopter heli, float yRaw, Vector3 dir)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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)
			Vector3 velocity = ((Vehicle)heli).rigidbody.velocity;
			float num = Mathf.Clamp01(0f - Vector3.Dot(dir, ((Vector3)(ref velocity)).normalized));
			float num2 = 1f + Mathf.Lerp(0f, heli.extraForceWhenStopping, num);
			float num3 = ComputeGameGroundEffect(heli, yRaw, dir) + yRaw * heli.rotorForce * num2;
			float num4 = (((Vehicle)heli).burning ? 0.3f : 1f);
			return dir * ((num3 - Physics.gravity.y - 0.5f) * num4);
		}

		private static float ComputeGameGroundEffect(Helicopter heli, float yRaw, Vector3 dir)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return Mathf.Clamp01(Mathf.Max(yRaw, 0f) * Vector3.Dot(dir, Vector3.up) * (20f - heli.altitude) * 0.1f) * heli.groundEffectAcceleration;
		}
	}
}