Decompiled source of SebLogiWheel v1.0.3

BepInEx\plugins\SebLogiWheel\SebLogiWheel.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SebCore;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("SebLogiWheel")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SebLogiWheel")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5B99A0FA-9A67-4748-9F89-4B0B8F0E2D60")]
[assembly: AssemblyFileVersion("1.0.3")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
public class LogitechGSDK
{
	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public struct LogiControllerPropertiesData
	{
		public bool forceEnable;

		public int overallGain;

		public int springGain;

		public int damperGain;

		public bool defaultSpringEnabled;

		public int defaultSpringGain;

		public bool combinePedals;

		public int wheelRange;

		public bool gameSettingsEnabled;

		public bool allowGameSettings;
	}

	[StructLayout(LayoutKind.Sequential, Pack = 2)]
	public struct DIJOYSTATE2ENGINES
	{
		public int lX;

		public int lY;

		public int lZ;

		public int lRx;

		public int lRy;

		public int lRz;

		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
		public int[] rglSlider;

		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
		public uint[] rgdwPOV;

		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
		public byte[] rgbButtons;

		public int lVX;

		public int lVY;

		public int lVZ;

		public int lVRx;

		public int lVRy;

		public int lVRz;

		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
		public int[] rglVSlider;

		public int lAX;

		public int lAY;

		public int lAZ;

		public int lARx;

		public int lARy;

		public int lARz;

		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
		public int[] rglASlider;

		public int lFX;

		public int lFY;

		public int lFZ;

		public int lFRx;

		public int lFRy;

		public int lFRz;

		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
		public int[] rglFSlider;
	}

	public const int LOGI_MAX_CONTROLLERS = 4;

	public const int LOGI_FORCE_NONE = -1;

	public const int LOGI_FORCE_SPRING = 0;

	public const int LOGI_FORCE_CONSTANT = 1;

	public const int LOGI_FORCE_DAMPER = 2;

	public const int LOGI_FORCE_SIDE_COLLISION = 3;

	public const int LOGI_FORCE_FRONTAL_COLLISION = 4;

	public const int LOGI_FORCE_DIRT_ROAD = 5;

	public const int LOGI_FORCE_BUMPY_ROAD = 6;

	public const int LOGI_FORCE_SLIPPERY_ROAD = 7;

	public const int LOGI_FORCE_SURFACE_EFFECT = 8;

	public const int LOGI_NUMBER_FORCE_EFFECTS = 9;

	public const int LOGI_FORCE_SOFTSTOP = 10;

	public const int LOGI_FORCE_CAR_AIRBORNE = 11;

	public const int LOGI_PERIODICTYPE_NONE = -1;

	public const int LOGI_PERIODICTYPE_SINE = 0;

	public const int LOGI_PERIODICTYPE_SQUARE = 1;

	public const int LOGI_PERIODICTYPE_TRIANGLE = 2;

	public const int LOGI_DEVICE_TYPE_NONE = -1;

	public const int LOGI_DEVICE_TYPE_WHEEL = 0;

	public const int LOGI_DEVICE_TYPE_JOYSTICK = 1;

	public const int LOGI_DEVICE_TYPE_GAMEPAD = 2;

	public const int LOGI_DEVICE_TYPE_OTHER = 3;

	public const int LOGI_NUMBER_DEVICE_TYPES = 4;

	public const int LOGI_MANUFACTURER_NONE = -1;

	public const int LOGI_MANUFACTURER_LOGITECH = 0;

	public const int LOGI_MANUFACTURER_MICROSOFT = 1;

	public const int LOGI_MANUFACTURER_OTHER = 2;

	public const int LOGI_MODEL_G27 = 0;

	public const int LOGI_MODEL_DRIVING_FORCE_GT = 1;

	public const int LOGI_MODEL_G25 = 2;

	public const int LOGI_MODEL_MOMO_RACING = 3;

	public const int LOGI_MODEL_MOMO_FORCE = 4;

	public const int LOGI_MODEL_DRIVING_FORCE_PRO = 5;

	public const int LOGI_MODEL_DRIVING_FORCE = 6;

	public const int LOGI_MODEL_NASCAR_RACING_WHEEL = 7;

	public const int LOGI_MODEL_FORMULA_FORCE = 8;

	public const int LOGI_MODEL_FORMULA_FORCE_GP = 9;

	public const int LOGI_MODEL_FORCE_3D_PRO = 10;

	public const int LOGI_MODEL_EXTREME_3D_PRO = 11;

	public const int LOGI_MODEL_FREEDOM_24 = 12;

	public const int LOGI_MODEL_ATTACK_3 = 13;

	public const int LOGI_MODEL_FORCE_3D = 14;

	public const int LOGI_MODEL_STRIKE_FORCE_3D = 15;

	public const int LOGI_MODEL_G940_JOYSTICK = 16;

	public const int LOGI_MODEL_G940_THROTTLE = 17;

	public const int LOGI_MODEL_G940_PEDALS = 18;

	public const int LOGI_MODEL_RUMBLEPAD = 19;

	public const int LOGI_MODEL_RUMBLEPAD_2 = 20;

	public const int LOGI_MODEL_CORDLESS_RUMBLEPAD_2 = 21;

	public const int LOGI_MODEL_CORDLESS_GAMEPAD = 22;

	public const int LOGI_MODEL_DUAL_ACTION_GAMEPAD = 23;

	public const int LOGI_MODEL_PRECISION_GAMEPAD_2 = 24;

	public const int LOGI_MODEL_CHILLSTREAM = 25;

	public const int LOGI_MODEL_G29 = 26;

	public const int LOGI_MODEL_G920 = 27;

	public const int LOGI_NUMBER_MODELS = 28;

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiSteeringInitialize(bool ignoreXInputControllers);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiUpdate();

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl)]
	public static extern IntPtr LogiGetStateENGINES(int index);

	public static DIJOYSTATE2ENGINES LogiGetStateCSharp(int index)
	{
		DIJOYSTATE2ENGINES result = default(DIJOYSTATE2ENGINES);
		result.rglSlider = new int[2];
		result.rgdwPOV = new uint[4];
		result.rgbButtons = new byte[128];
		result.rglVSlider = new int[2];
		result.rglASlider = new int[2];
		result.rglFSlider = new int[2];
		try
		{
			result = (DIJOYSTATE2ENGINES)Marshal.PtrToStructure(LogiGetStateENGINES(index), typeof(DIJOYSTATE2ENGINES));
			return result;
		}
		catch (ArgumentException)
		{
		}
		return result;
	}

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiGetDevicePath(int index, StringBuilder str, int size);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiGetFriendlyProductName(int index, StringBuilder str, int size);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiIsConnected(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiIsDeviceConnected(int index, int deviceType);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiIsManufacturerConnected(int index, int manufacturerName);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiIsModelConnected(int index, int modelName);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiButtonTriggered(int index, int buttonNbr);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiButtonReleased(int index, int buttonNbr);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiButtonIsPressed(int index, int buttonNbr);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiGenerateNonLinearValues(int index, int nonLinCoeff);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern int LogiGetNonLinearValue(int index, int inputValue);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiHasForceFeedback(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiIsPlaying(int index, int forceType);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlaySpringForce(int index, int offsetPercentage, int saturationPercentage, int coefficientPercentage);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiStopSpringForce(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlayConstantForce(int index, int magnitudePercentage);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiStopConstantForce(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlayDamperForce(int index, int coefficientPercentage);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiStopDamperForce(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlaySideCollisionForce(int index, int magnitudePercentage);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlayFrontalCollisionForce(int index, int magnitudePercentage);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlayDirtRoadEffect(int index, int magnitudePercentage);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiStopDirtRoadEffect(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlayBumpyRoadEffect(int index, int magnitudePercentage);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiStopBumpyRoadEffect(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlaySlipperyRoadEffect(int index, int magnitudePercentage);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiStopSlipperyRoadEffect(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlaySurfaceEffect(int index, int type, int magnitudePercentage, int period);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiStopSurfaceEffect(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlayCarAirborne(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiStopCarAirborne(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlaySoftstopForce(int index, int usableRangePercentage);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiStopSoftstopForce(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiSetPreferredControllerProperties(LogiControllerPropertiesData properties);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiGetCurrentControllerProperties(int index, ref LogiControllerPropertiesData properties);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern int LogiGetShifterMode(int index);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiSetOperatingRange(int index, int range);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiGetOperatingRange(int index, ref int range);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern bool LogiPlayLeds(int index, float currentRPM, float rpmFirstLedTurnsOn, float rpmRedLine);

	[DllImport("LogitechSteeringWheelEnginesWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
	public static extern void LogiSteeringShutdown();
}
namespace SebLogiWheel
{
	[BepInPlugin("shibe.easydeliveryco.seblogiwheel", "SebLogiWheel", "1.0.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(sCarController), "SetInput", new Type[] { typeof(Vector2) })]
		private static class CarController_SetInput_Vector2_Patch
		{
			private static readonly FieldRef<sCarController, Vector2> TargetInputRef = AccessTools.FieldRefAccess<sCarController, Vector2>("targetInput");

			private static bool Prefix(sCarController __instance, Vector2 input)
			{
				//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_0068: 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_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null)
				{
					return true;
				}
				if (!ShouldApply() || __instance.GuyActive)
				{
					return true;
				}
				if (!TryGetWheelLastInput(out var _, out var _))
				{
					return true;
				}
				Vector2 val = input;
				if (__instance.throttleCurve != null)
				{
					val.y = __instance.throttleCurve.Evaluate(Math.Abs(val.y)) * (float)Math.Sign(val.y);
				}
				TargetInputRef.Invoke(__instance) = val;
				return false;
			}
		}

		[HarmonyPatch(typeof(sCarController), "Move")]
		private static class CarController_Move_Prefix_Patch
		{
			private static void Prefix(sCarController __instance)
			{
				if (!((Object)(object)__instance == (Object)null) && ShouldApply() && !__instance.GuyActive && TryGetWheelLastInput(out var steer, out var accel))
				{
					__instance.input.x = steer;
					__instance.input.y = accel;
				}
			}
		}

		internal enum PedalKind
		{
			Throttle,
			Brake,
			Clutch
		}

		internal enum AxisId
		{
			lX,
			lY,
			lZ,
			lRx,
			lRy,
			lRz,
			slider0,
			slider1
		}

		internal enum SpeedUnit
		{
			Kmh,
			Mph
		}

		internal enum HudReadoutAnchor
		{
			BottomLeft,
			BottomRight
		}

		internal enum ButtonBindAction
		{
			InteractOk = 0,
			Back = 1,
			MapItems = 2,
			Pause = 3,
			Camera = 5,
			ResetVehicle = 6,
			Headlights = 7,
			Horn = 8,
			RadioPower = 9,
			RadioScanToggle = 10,
			RadioScanLeft = 11,
			RadioScanRight = 12,
			ToggleGearbox = 13,
			ShiftUp = 14,
			ShiftDown = 15,
			IgnitionToggle = 16
		}

		internal enum BindingLayer
		{
			Normal,
			Modified
		}

		internal enum BindingKind
		{
			None,
			Button,
			Pov
		}

		internal struct BindingInput
		{
			public BindingKind Kind;

			public int Code;
		}

		private struct LogiDeviceSnapshot
		{
			public int Index;

			public bool Connected;

			public bool IsWheel;

			public bool IsGamepad;

			public bool IsJoystick;

			public bool IsLogitech;

			public bool IsG920;

			public bool IsG29;

			public int Vid;

			public int Pid;

			public string Name;

			public string Path;
		}

		internal enum FfbTestEffect
		{
			None,
			Shake,
			Bumpy
		}

		[HarmonyPatch(typeof(InteriorInteraction), "AnimateSteeringWheel")]
		private static class InteriorInteraction_AnimateSteeringWheel_Patch
		{
			private static readonly FieldRef<InteriorInteraction, sCarController> CarRef = AccessTools.FieldRefAccess<InteriorInteraction, sCarController>("car");

			private static readonly FieldRef<InteriorInteraction, Transform> HandPivotRef = AccessTools.FieldRefAccess<InteriorInteraction, Transform>("handPivot");

			private static readonly FieldRef<InteriorInteraction, Vector3[]> HandRestLocalPositionsRef = AccessTools.FieldRefAccess<InteriorInteraction, Vector3[]>("handRestLocalPositions");

			private static bool Prefix(InteriorInteraction __instance)
			{
				//IL_008c: 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_0132: Unknown result type (might be due to invalid IL or missing references)
				//IL_013d: 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_0103: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null)
				{
					return true;
				}
				if (!ShouldApply())
				{
					return true;
				}
				if (!TryGetWheelLastInput(out var _, out var accel))
				{
					return true;
				}
				sCarController val = CarRef.Invoke(__instance);
				if ((Object)(object)val == (Object)null)
				{
					return true;
				}
				if (val.GuyActive)
				{
					return true;
				}
				if ((Object)(object)__instance.steeringWheel == (Object)null)
				{
					return false;
				}
				if (!TryGetWheelLastInputRecent(0.1f, out var steer2, out accel))
				{
					steer2 = Mathf.Clamp(val.input.x, -1f, 1f);
				}
				float num = steer2 * 420f;
				__instance.steeringWheel.localEulerAngles = Vector3.up * num;
				if ((Object)(object)__instance.handRest != (Object)null && (Object)(object)__instance.hand != (Object)null)
				{
					float num2 = Mathf.Clamp01((Mathf.Abs(num) - 30f) / 60f);
					Vector3[] array = HandRestLocalPositionsRef.Invoke(__instance);
					if (array != null && array.Length >= 2)
					{
						__instance.handRest.localPosition = array[(!(num < 0f)) ? 1u : 0u];
					}
					Transform val2 = HandPivotRef.Invoke(__instance);
					if ((Object)(object)val2 != (Object)null)
					{
						((Component)__instance.hand).transform.position = Vector3.Lerp(val2.position, __instance.handRest.position, num2);
					}
				}
				return false;
			}
		}

		private static float _ffbNextUpdateTime;

		private static int _ffbLastDamper = int.MinValue;

		private static int _ffbLastSpring = int.MinValue;

		private static int _ffbLastDirt = int.MinValue;

		private static int _ffbLastBumpy = int.MinValue;

		private static ManualLogSource _log;

		private static ConfigEntry<bool> _debugLogging;

		private static ConfigEntry<bool> _logDetectedDevices;

		private static ConfigEntry<bool> _ignoreXInputControllers;

		private const string PrefPrefixNew = "ELWS_";

		private const string PrefPrefixOld = "G920";

		internal const string PrefKeyFfbEnabled = "ELWS_FfbEnabled";

		internal const string PrefKeyFfbOverall = "ELWS_FfbOverall";

		internal const string PrefKeyFfbSpring = "ELWS_FfbSpring";

		internal const string PrefKeyFfbDamper = "ELWS_FfbDamper";

		internal const string PrefKeyWheelRange = "ELWS_WheelRange";

		internal const string PrefKeyCalSteerCenter = "ELWS_Cal_SteerCenter";

		internal const string PrefKeyCalSteerLeft = "ELWS_Cal_SteerLeft";

		internal const string PrefKeyCalSteerRight = "ELWS_Cal_SteerRight";

		internal const string PrefKeyCalThrottleReleased = "ELWS_Cal_ThrottleReleased";

		internal const string PrefKeyCalThrottlePressed = "ELWS_Cal_ThrottlePressed";

		internal const string PrefKeyCalBrakeReleased = "ELWS_Cal_BrakeReleased";

		internal const string PrefKeyCalBrakePressed = "ELWS_Cal_BrakePressed";

		internal const string PrefKeyCalClutchReleased = "ELWS_Cal_ClutchReleased";

		internal const string PrefKeyCalClutchPressed = "ELWS_Cal_ClutchPressed";

		internal const string PrefKeySteeringGain = "ELWS_SteerGain";

		internal const string PrefKeySteeringDeadzone = "ELWS_SteerDeadzone";

		internal const string PrefKeySteeringAxis = "ELWS_Axis_Steer";

		internal const string PrefKeyThrottleAxis = "ELWS_Axis_Throttle";

		internal const string PrefKeyBrakeAxis = "ELWS_Axis_Brake";

		internal const string PrefKeyClutchAxis = "ELWS_Axis_Clutch";

		internal const string PrefKeyManualTransmissionEnabled = "ELWS_ManualTransmission";

		internal const string PrefKeyHudShowSpeed = "ELWS_HudShowSpeed";

		internal const string PrefKeyHudShowTach = "ELWS_HudShowTach";

		internal const string PrefKeyHudShowGear = "ELWS_HudShowGear";

		internal const string PrefKeyHudSpeedUnits = "ELWS_HudSpeedUnits";

		internal const string PrefKeyHudReadoutAnchor = "ELWS_HudReadoutAnchor";

		internal const string PrefKeyHudSpeedAnchor = "ELWS_HudSpeedAnchor";

		internal const string PrefKeyHudTachAnchor = "ELWS_HudTachAnchor";

		internal const string PrefKeyHudGearAnchor = "ELWS_HudGearAnchor";

		internal const string PrefKeyIgnitionEnabled = "ELWS_IgnitionEnabled";

		internal const string PrefKeyIgnitionFeatureEnabled = "ELWS_IgnitionFeatureEnabled";

		internal const string PrefKeyIgnitionHoldSeconds = "ELWS_IgnitionHoldSeconds";

		internal const string PrefKeyIgnitionSfxEnabled = "ELWS_IgnitionSfxEnabled";

		internal const string PrefKeyHeadlightIntensityMult = "ELWS_HeadlightIntensityMult";

		internal const string PrefKeyHeadlightRangeMult = "ELWS_HeadlightRangeMult";

		internal const string PrefKeyManualSpeedMultForward = "ELWS_ManualSpeedMultFwd";

		internal const string PrefKeyManualSpeedMultReverse = "ELWS_ManualSpeedMultRev";

		internal const string PrefKeyManualGearCount = "ELWS_ManualGearCount";

		private const int BindingPovOffset = 1000;

		private const string PrefKeyBindModifier = "ELWS_Bind_Modifier";

		private const string PrefKeyPrefMigrationDone = "ELWS_MigratedFromG920_v1";

		private static int _wheelInputCacheFrame = -1;

		private static bool _wheelInputCacheValid;

		private static LogitechGSDK.DIJOYSTATE2ENGINES _wheelInputCacheState;

		private static bool[] _wheelButtonsDown;

		private static bool[] _wheelButtonsPressed;

		private static bool[] _wheelButtonsReleased;

		private static bool[] _wheelPovDown;

		private static bool[] _wheelPovPressed;

		private static bool[] _wheelPovReleased;

		private static int _wheelPovDirDown = -1;

		private static bool _logiInitAttempted;

		private static bool _logiAvailable;

		private static bool _logiConnected;

		private static int _logiIndex;

		private static int _logiInitAttemptCount;

		private static float _logiNextInitAttemptTime;

		private static bool _logiIgnoreXInputUsed;

		private static bool _logiWasConnected;

		private static string _logiLastName;

		private static string _logiLastPath;

		private static bool _logiSelectionDone;

		private static float _logiLastSelectionAttemptTime;

		private static bool _logiWarnedSelectedNotWheel;

		private static bool _isInWalkingMode;

		private static float _currentSpeedKmh;

		private static bool _isOffRoad;

		private static bool _isSliding;

		private static sCarController _currentCar;

		private static float _lastThrottle01;

		private static float _neutralRev01;

		private static bool _manualTransmissionEnabled;

		private static int _manualGear = 1;

		private static int _wheelLastUpdateFrame;

		private static float _wheelLastUpdateTime;

		private static float _wheelLastSteer;

		private static float _wheelLastAccel;

		private static float _wheelMenuHeartbeatTime;

		private static float _ffbPageHeartbeatTime;

		private static float _bindingCaptureHeartbeatTime;

		private static float _calibrationWizardHeartbeatTime;

		private static bool _openCalibrationWizardRequested;

		private static bool _openAxisMappingRequested;

		private static FfbTestEffect _ffbTestEffect;

		private static float _ffbTestEndTime;

		public const string PluginGuid = "shibe.easydeliveryco.seblogiwheel";

		public const string PluginName = "SebLogiWheel";

		public const string PluginVersion = "1.0.3";

		private static Plugin _instance;

		private const float IgnitionColdAfterSeconds = 30f;

		private static float _ignitionHoldStart = -1f;

		private static bool _ignitionHoldConsumed;

		private static bool _ignitionHoldWasDown;

		private static bool _ignitionIgnoreHoldUntilRelease;

		private static float _ignitionOffSince = -1f;

		private static bool _ignitionPrevHeadlightsOn;

		private static bool _ignitionPrevRadioOn;

		private static GameObject _ignitionHoldSfxGo;

		private static AudioSource _ignitionHoldSfxSource;

		private static bool _suppressNextIgnitionOnSfx;

		private static readonly Dictionary<int, (float intensity, float range)> _lightDefaults = new Dictionary<int, (float, float)>();

		private static Type _headlightsRuntimeType;

		private static FieldInfo _headlightsHeadLightsField;

		private static FieldInfo _headlightsCarMatField;

		private static FieldInfo _headlightsEmissiveRegularField;

		private static FieldInfo _headlightsEmissiveBreakingField;

		private static FieldInfo _headlightsHeadlightsOnField;

		private static FieldInfo _headlightsModelField;

		private static Texture2D _ignitionBlackEmissiveTex;

		private static Type _lensFlareSrpType;

		private static readonly Dictionary<int, bool> _lensFlareSrpDefaults = new Dictionary<int, bool>();

		private static Type _flareIntensityType;

		private static readonly Dictionary<int, bool> _flareIntensityDefaults = new Dictionary<int, bool>();

		private static readonly Dictionary<int, bool> _artifactRendererDefaults = new Dictionary<int, bool>();

		private static float _ignitionEnforceLastLogTime = -999f;

		private static float _ignitionBindMissingLastLogTime = -999f;

		private static readonly Dictionary<int, (float maxSpeedScale, float drivePowerScale)> _carScaleDefaults = new Dictionary<int, (float, float)>();

		private static float _rpmHudSmooth;

		private static Type _engineSfxRuntimeType;

		private static FieldInfo _engineCarField;

		private static FieldInfo _engineIdleField;

		private static FieldInfo _engineDriveField;

		private static FieldInfo _engineIntenseField;

		private static FieldInfo _engineDistortionField;

		private static readonly Dictionary<int, float> _enginePitchMulApplied = new Dictionary<int, float>();

		internal static void ClearAllUserPrefs()
		{
			string[] array = new string[39]
			{
				"ELWS_FfbEnabled", "ELWS_FfbOverall", "ELWS_FfbSpring", "ELWS_FfbDamper", "ELWS_WheelRange", "ELWS_SteerGain", "ELWS_SteerDeadzone", "ELWS_Axis_Steer", "ELWS_Axis_Throttle", "ELWS_Axis_Brake",
				"ELWS_Axis_Clutch", "ELWS_Cal_SteerCenter", "ELWS_Cal_SteerLeft", "ELWS_Cal_SteerRight", "ELWS_Cal_ThrottleReleased", "ELWS_Cal_ThrottlePressed", "ELWS_Cal_BrakeReleased", "ELWS_Cal_BrakePressed", "ELWS_Cal_ClutchReleased", "ELWS_Cal_ClutchPressed",
				"ELWS_ManualTransmission", "ELWS_HudShowSpeed", "ELWS_HudShowTach", "ELWS_HudShowGear", "ELWS_HudSpeedUnits", "ELWS_HudReadoutAnchor", "ELWS_HudSpeedAnchor", "ELWS_HudTachAnchor", "ELWS_HudGearAnchor", "ELWS_IgnitionEnabled",
				"ELWS_IgnitionFeatureEnabled", "ELWS_IgnitionHoldSeconds", "ELWS_IgnitionSfxEnabled", "ELWS_HeadlightIntensityMult", "ELWS_HeadlightRangeMult", "ELWS_ManualSpeedMultFwd", "ELWS_ManualSpeedMultRev", "ELWS_ManualGearCount", "ELWS_Bind_Modifier"
			};
			foreach (string text in array)
			{
				if (!string.IsNullOrWhiteSpace(text))
				{
					PlayerPrefs.DeleteKey(text);
					string text2 = OldKeyFromNew(text);
					if (!string.IsNullOrEmpty(text2))
					{
						PlayerPrefs.DeleteKey(text2);
					}
				}
			}
			BindingLayer[] array2 = (BindingLayer[])Enum.GetValues(typeof(BindingLayer));
			foreach (BindingLayer layer in array2)
			{
				ButtonBindAction[] array3 = (ButtonBindAction[])Enum.GetValues(typeof(ButtonBindAction));
				foreach (ButtonBindAction action in array3)
				{
					string bindPrefKey = GetBindPrefKey(layer, action);
					string legacyBindPrefKey = GetLegacyBindPrefKey(layer, action);
					PlayerPrefs.DeleteKey(bindPrefKey);
					PlayerPrefs.DeleteKey(legacyBindPrefKey);
					string text3 = OldKeyFromNew(bindPrefKey);
					string text4 = OldKeyFromNew(legacyBindPrefKey);
					if (!string.IsNullOrEmpty(text3))
					{
						PlayerPrefs.DeleteKey(text3);
					}
					if (!string.IsNullOrEmpty(text4))
					{
						PlayerPrefs.DeleteKey(text4);
					}
				}
			}
			PlayerPrefs.DeleteKey("ELWS_MigratedFromG920_v1");
			PlayerPrefs.Save();
		}

		private static string OldKeyFromNew(string newKey)
		{
			if (string.IsNullOrWhiteSpace(newKey))
			{
				return string.Empty;
			}
			if (!newKey.StartsWith("ELWS_", StringComparison.Ordinal))
			{
				return string.Empty;
			}
			return "G920" + newKey.Substring("ELWS_".Length);
		}

		internal static void MigratePrefsFromG920IfNeeded()
		{
			if (PlayerPrefs.GetInt("ELWS_MigratedFromG920_v1", 0) != 0)
			{
				return;
			}
			try
			{
				string[] array = new string[29]
				{
					"ELWS_FfbEnabled", "ELWS_WheelRange", "ELWS_Axis_Steer", "ELWS_Axis_Throttle", "ELWS_Axis_Brake", "ELWS_Axis_Clutch", "ELWS_Cal_SteerCenter", "ELWS_Cal_SteerLeft", "ELWS_Cal_SteerRight", "ELWS_Cal_ThrottleReleased",
					"ELWS_Cal_ThrottlePressed", "ELWS_Cal_BrakeReleased", "ELWS_Cal_BrakePressed", "ELWS_Cal_ClutchReleased", "ELWS_Cal_ClutchPressed", "ELWS_ManualTransmission", "ELWS_HudShowSpeed", "ELWS_HudShowTach", "ELWS_HudShowGear", "ELWS_HudSpeedUnits",
					"ELWS_HudReadoutAnchor", "ELWS_HudSpeedAnchor", "ELWS_HudTachAnchor", "ELWS_HudGearAnchor", "ELWS_IgnitionEnabled", "ELWS_IgnitionFeatureEnabled", "ELWS_IgnitionSfxEnabled", "ELWS_ManualGearCount", "ELWS_Bind_Modifier"
				};
				string[] array2 = new string[9] { "ELWS_FfbOverall", "ELWS_FfbSpring", "ELWS_FfbDamper", "ELWS_SteerGain", "ELWS_SteerDeadzone", "ELWS_HeadlightIntensityMult", "ELWS_HeadlightRangeMult", "ELWS_ManualSpeedMultFwd", "ELWS_ManualSpeedMultRev" };
				int num = 0;
				foreach (string text in array)
				{
					string text2 = OldKeyFromNew(text);
					if (!string.IsNullOrEmpty(text2) && !PlayerPrefs.HasKey(text) && PlayerPrefs.HasKey(text2))
					{
						PlayerPrefs.SetInt(text, PlayerPrefs.GetInt(text2));
						num++;
					}
				}
				foreach (string text3 in array2)
				{
					string text4 = OldKeyFromNew(text3);
					if (!string.IsNullOrEmpty(text4) && !PlayerPrefs.HasKey(text3) && PlayerPrefs.HasKey(text4))
					{
						PlayerPrefs.SetFloat(text3, PlayerPrefs.GetFloat(text4));
						num++;
					}
				}
				BindingLayer[] array3 = (BindingLayer[])Enum.GetValues(typeof(BindingLayer));
				foreach (BindingLayer layer in array3)
				{
					ButtonBindAction[] array4 = (ButtonBindAction[])Enum.GetValues(typeof(ButtonBindAction));
					foreach (ButtonBindAction action in array4)
					{
						string bindPrefKey = GetBindPrefKey(layer, action);
						if (PlayerPrefs.HasKey(bindPrefKey))
						{
							continue;
						}
						string text5 = OldKeyFromNew(bindPrefKey);
						if (!string.IsNullOrEmpty(text5) && PlayerPrefs.HasKey(text5))
						{
							PlayerPrefs.SetInt(bindPrefKey, PlayerPrefs.GetInt(text5));
							num++;
							continue;
						}
						string text6 = OldKeyFromNew(GetLegacyBindPrefKey(layer, action));
						if (!string.IsNullOrEmpty(text6) && PlayerPrefs.HasKey(text6))
						{
							PlayerPrefs.SetInt(bindPrefKey, PlayerPrefs.GetInt(text6));
							num++;
						}
					}
				}
				PlayerPrefs.SetInt("ELWS_MigratedFromG920_v1", 1);
				PlayerPrefs.Save();
				if (num > 0)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogInfo((object)("Migrated " + num + " PlayerPrefs keys from G920_* to ELWS_*"));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Prefs migration failed: " + ex.Message));
				}
				PlayerPrefs.SetInt("ELWS_MigratedFromG920_v1", 1);
				PlayerPrefs.Save();
			}
		}

		private static string GetBindPrefKey(BindingLayer layer, ButtonBindAction action)
		{
			int num = (int)layer;
			string text = num.ToString();
			num = (int)action;
			return "ELWS_Bind_" + text + "_" + num;
		}

		private static string GetLegacyBindPrefKey(BindingLayer layer, ButtonBindAction action)
		{
			return "ELWS_Bind_" + layer.ToString() + "_" + action;
		}

		internal static BindingInput GetBinding(BindingLayer layer, ButtonBindAction action)
		{
			int @int = PlayerPrefs.GetInt(GetBindPrefKey(layer, action), -1);
			if (@int < 0)
			{
				@int = PlayerPrefs.GetInt(GetLegacyBindPrefKey(layer, action), -1);
			}
			BindingInput result;
			if (@int < 0)
			{
				result = default(BindingInput);
				result.Kind = BindingKind.None;
				result.Code = 0;
				return result;
			}
			if (@int >= 1000)
			{
				result = default(BindingInput);
				result.Kind = BindingKind.Pov;
				result.Code = Mathf.Clamp(@int - 1000, 0, 3);
				return result;
			}
			result = default(BindingInput);
			result.Kind = BindingKind.Button;
			result.Code = Mathf.Clamp(@int, 0, 127);
			return result;
		}

		internal static void SetBinding(BindingLayer layer, ButtonBindAction action, BindingInput input)
		{
			int num = ((input.Kind == BindingKind.Button) ? Mathf.Clamp(input.Code, 0, 127) : ((input.Kind != BindingKind.Pov) ? (-1) : (1000 + Mathf.Clamp(input.Code, 0, 3))));
			PlayerPrefs.SetInt(GetBindPrefKey(layer, action), num);
		}

		internal static bool TryGetPovDir(out int dir)
		{
			dir = -1;
			if (!TryGetCachedWheelState(out var state))
			{
				return false;
			}
			uint pov = uint.MaxValue;
			if (state.rgdwPOV != null && state.rgdwPOV.Length != 0)
			{
				pov = state.rgdwPOV[0];
			}
			dir = PovToDir(pov);
			return true;
		}

		internal static bool TryGetPov8Vector(out Vector2 v)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_012c: Unknown result type (might be due to invalid IL or missing references)
			v = Vector2.zero;
			if (!TryGetCachedWheelState(out var state))
			{
				return false;
			}
			uint num = uint.MaxValue;
			if (state.rgdwPOV != null && state.rgdwPOV.Length != 0)
			{
				num = state.rgdwPOV[0];
			}
			if (num == uint.MaxValue)
			{
				return true;
			}
			switch (Mathf.RoundToInt((float)(int)(num % 36000) / 4500f) % 8)
			{
			case 0:
				v = new Vector2(0f, -1f);
				break;
			case 1:
				v = new Vector2(-1f, -1f);
				break;
			case 2:
				v = new Vector2(-1f, 0f);
				break;
			case 3:
				v = new Vector2(-1f, 1f);
				break;
			case 4:
				v = new Vector2(0f, 1f);
				break;
			case 5:
				v = new Vector2(1f, 1f);
				break;
			case 6:
				v = new Vector2(1f, 0f);
				break;
			default:
				v = new Vector2(1f, -1f);
				break;
			}
			return true;
		}

		internal static BindingInput GetModifierBinding()
		{
			int @int = PlayerPrefs.GetInt("ELWS_Bind_Modifier", -1);
			BindingInput result;
			if (@int < 0)
			{
				result = default(BindingInput);
				result.Kind = BindingKind.None;
				result.Code = 0;
				return result;
			}
			if (@int >= 1000)
			{
				result = default(BindingInput);
				result.Kind = BindingKind.Pov;
				result.Code = Mathf.Clamp(@int - 1000, 0, 3);
				return result;
			}
			result = default(BindingInput);
			result.Kind = BindingKind.Button;
			result.Code = Mathf.Clamp(@int, 0, 127);
			return result;
		}

		internal static void SetModifierBinding(BindingInput input)
		{
			int num = ((input.Kind == BindingKind.Button) ? Mathf.Clamp(input.Code, 0, 127) : ((input.Kind != BindingKind.Pov) ? (-1) : (1000 + Mathf.Clamp(input.Code, 0, 3))));
			PlayerPrefs.SetInt("ELWS_Bind_Modifier", num);
		}

		internal static string GetBindingLabel(BindingInput input)
		{
			if (input.Kind == BindingKind.Button)
			{
				return "But. " + (Mathf.Clamp(input.Code, 0, 127) + 1);
			}
			if (input.Kind == BindingKind.Pov)
			{
				return Mathf.Clamp(input.Code, 0, 3) switch
				{
					0 => "DP Up", 
					1 => "DP Right", 
					2 => "DP Down", 
					_ => "DP Left", 
				};
			}
			return "None";
		}

		internal static string GetChordLabel(BindingInput input, bool modified)
		{
			string bindingLabel = GetBindingLabel(input);
			if (!modified || input.Kind == BindingKind.None)
			{
				return bindingLabel;
			}
			return "M+" + bindingLabel;
		}

		internal static string GetActionLabel(ButtonBindAction action)
		{
			return action switch
			{
				ButtonBindAction.InteractOk => "Interact", 
				ButtonBindAction.Back => "Back", 
				ButtonBindAction.MapItems => "Map/Items", 
				ButtonBindAction.Pause => "Pause", 
				ButtonBindAction.Camera => "Camera", 
				ButtonBindAction.ResetVehicle => "Reset", 
				ButtonBindAction.Headlights => "Lights", 
				ButtonBindAction.Horn => "Horn", 
				ButtonBindAction.RadioPower => "Radio Pwr", 
				ButtonBindAction.RadioScanToggle => "Scan", 
				ButtonBindAction.RadioScanLeft => "Prev Ch", 
				ButtonBindAction.RadioScanRight => "Next Ch", 
				ButtonBindAction.ToggleGearbox => "Gearbox", 
				ButtonBindAction.ShiftUp => "Shift Up", 
				ButtonBindAction.ShiftDown => "Shift Down", 
				ButtonBindAction.IgnitionToggle => "Ignition(Hold)", 
				_ => action.ToString(), 
			};
		}

		private static void EnsureWheelInputArrays()
		{
			if (_wheelButtonsDown == null)
			{
				_wheelButtonsDown = new bool[128];
			}
			if (_wheelButtonsPressed == null)
			{
				_wheelButtonsPressed = new bool[128];
			}
			if (_wheelButtonsReleased == null)
			{
				_wheelButtonsReleased = new bool[128];
			}
			if (_wheelPovDown == null)
			{
				_wheelPovDown = new bool[4];
			}
			if (_wheelPovPressed == null)
			{
				_wheelPovPressed = new bool[4];
			}
			if (_wheelPovReleased == null)
			{
				_wheelPovReleased = new bool[4];
			}
		}

		private static int PovToDir(uint pov)
		{
			if (pov == uint.MaxValue)
			{
				return -1;
			}
			return (int)(pov % 36000 + 4500) / 9000 % 4;
		}

		private static void UpdateWheelInputCache()
		{
			EnsureWheelInputArrays();
			int frameCount = Time.frameCount;
			if (frameCount == _wheelInputCacheFrame)
			{
				return;
			}
			_wheelInputCacheFrame = frameCount;
			Array.Clear(_wheelButtonsPressed, 0, _wheelButtonsPressed.Length);
			Array.Clear(_wheelButtonsReleased, 0, _wheelButtonsReleased.Length);
			Array.Clear(_wheelPovPressed, 0, _wheelPovPressed.Length);
			Array.Clear(_wheelPovReleased, 0, _wheelPovReleased.Length);
			_wheelInputCacheValid = TryGetLogiState(out var state);
			if (!_wheelInputCacheValid)
			{
				return;
			}
			_wheelInputCacheState = state;
			if (state.rgbButtons != null)
			{
				int num = Math.Min(state.rgbButtons.Length, _wheelButtonsDown.Length);
				for (int i = 0; i < num; i++)
				{
					bool flag = state.rgbButtons[i] >= 128;
					if (flag && !_wheelButtonsDown[i])
					{
						_wheelButtonsPressed[i] = true;
					}
					else if (!flag && _wheelButtonsDown[i])
					{
						_wheelButtonsReleased[i] = true;
					}
					_wheelButtonsDown[i] = flag;
				}
			}
			int num2 = -1;
			if (state.rgdwPOV != null && state.rgdwPOV.Length != 0)
			{
				num2 = PovToDir(state.rgdwPOV[0]);
			}
			if (num2 != _wheelPovDirDown)
			{
				if (_wheelPovDirDown >= 0)
				{
					_wheelPovReleased[_wheelPovDirDown] = true;
				}
				if (num2 >= 0)
				{
					_wheelPovPressed[num2] = true;
				}
			}
			_wheelPovDirDown = num2;
			for (int j = 0; j < 4; j++)
			{
				_wheelPovDown[j] = num2 == j;
			}
		}

		internal static bool TryGetCachedWheelState(out LogitechGSDK.DIJOYSTATE2ENGINES state)
		{
			UpdateWheelInputCache();
			state = _wheelInputCacheState;
			return _wheelInputCacheValid;
		}

		internal static bool TryCaptureNextBinding(out BindingInput input)
		{
			input = default(BindingInput);
			UpdateWheelInputCache();
			if (!_wheelInputCacheValid)
			{
				return false;
			}
			for (int i = 0; i < _wheelButtonsPressed.Length; i++)
			{
				if (_wheelButtonsPressed[i])
				{
					input = new BindingInput
					{
						Kind = BindingKind.Button,
						Code = i
					};
					return true;
				}
			}
			for (int j = 0; j < _wheelPovPressed.Length; j++)
			{
				if (_wheelPovPressed[j])
				{
					input = new BindingInput
					{
						Kind = BindingKind.Pov,
						Code = j
					};
					return true;
				}
			}
			return false;
		}

		internal static bool IsBindingDownForCurrentFrame(BindingInput input)
		{
			UpdateWheelInputCache();
			if (!_wheelInputCacheValid)
			{
				return false;
			}
			return IsBindingDown(input);
		}

		internal static bool IsBindingPressedThisFrameForCurrentFrame(BindingInput input)
		{
			UpdateWheelInputCache();
			if (!_wheelInputCacheValid)
			{
				return false;
			}
			return IsBindingPressedThisFrame(input);
		}

		internal static bool IsBindingReleasedThisFrameForCurrentFrame(BindingInput input)
		{
			UpdateWheelInputCache();
			if (!_wheelInputCacheValid)
			{
				return false;
			}
			return IsBindingReleasedThisFrame(input);
		}

		private static bool IsBindingDown(BindingInput input)
		{
			if (input.Kind == BindingKind.Button)
			{
				int num = Mathf.Clamp(input.Code, 0, 127);
				if (_wheelButtonsDown != null && num < _wheelButtonsDown.Length)
				{
					return _wheelButtonsDown[num];
				}
				return false;
			}
			if (input.Kind == BindingKind.Pov)
			{
				int num2 = Mathf.Clamp(input.Code, 0, 3);
				if (_wheelPovDown != null && num2 < _wheelPovDown.Length)
				{
					return _wheelPovDown[num2];
				}
				return false;
			}
			return false;
		}

		private static bool IsBindingPressedThisFrame(BindingInput input)
		{
			if (input.Kind == BindingKind.Button)
			{
				int num = Mathf.Clamp(input.Code, 0, 127);
				if (_wheelButtonsPressed != null && num < _wheelButtonsPressed.Length)
				{
					return _wheelButtonsPressed[num];
				}
				return false;
			}
			if (input.Kind == BindingKind.Pov)
			{
				int num2 = Mathf.Clamp(input.Code, 0, 3);
				if (_wheelPovPressed != null && num2 < _wheelPovPressed.Length)
				{
					return _wheelPovPressed[num2];
				}
				return false;
			}
			return false;
		}

		private static bool IsBindingReleasedThisFrame(BindingInput input)
		{
			if (input.Kind == BindingKind.Button)
			{
				int num = Mathf.Clamp(input.Code, 0, 127);
				if (_wheelButtonsReleased != null && num < _wheelButtonsReleased.Length)
				{
					return _wheelButtonsReleased[num];
				}
				return false;
			}
			if (input.Kind == BindingKind.Pov)
			{
				int num2 = Mathf.Clamp(input.Code, 0, 3);
				if (_wheelPovReleased != null && num2 < _wheelPovReleased.Length)
				{
					return _wheelPovReleased[num2];
				}
				return false;
			}
			return false;
		}

		internal static int GetManualGearCount()
		{
			return Mathf.Clamp(PlayerPrefs.GetInt("ELWS_ManualGearCount", 5), 3, 6);
		}

		internal static void SetManualGearCount(int count)
		{
			count = Mathf.Clamp(count, 3, 6);
			PlayerPrefs.SetInt("ELWS_ManualGearCount", count);
			if (_manualGear > count)
			{
				_manualGear = count;
			}
		}

		internal static int NextManualGearCount(int count)
		{
			count++;
			if (count > 6)
			{
				count = 3;
			}
			return count;
		}

		internal static bool GetManualTransmissionEnabled()
		{
			return PlayerPrefs.GetInt("ELWS_ManualTransmission", 0) != 0;
		}

		internal static void SetManualTransmissionEnabled(bool enabled)
		{
			_manualTransmissionEnabled = enabled;
			PlayerPrefs.SetInt("ELWS_ManualTransmission", enabled ? 1 : 0);
			if (!enabled)
			{
				_manualGear = Mathf.Clamp(_manualGear, 1, GetManualGearCount());
			}
			else if (_manualGear == 0)
			{
				_manualGear = 1;
			}
		}

		internal static int GetManualGear()
		{
			return _manualGear;
		}

		internal static string GetManualGearLabel()
		{
			if (_manualGear < 0)
			{
				return "R";
			}
			if (_manualGear == 0)
			{
				return "N";
			}
			return _manualGear.ToString();
		}

		internal static bool GetHudShowSpeed()
		{
			return PlayerPrefs.GetInt("ELWS_HudShowSpeed", 1) != 0;
		}

		internal static void SetHudShowSpeed(bool enabled)
		{
			PlayerPrefs.SetInt("ELWS_HudShowSpeed", enabled ? 1 : 0);
		}

		internal static bool GetIgnitionEnabled()
		{
			return PlayerPrefs.GetInt("ELWS_IgnitionEnabled", 1) != 0;
		}

		internal static void SetIgnitionEnabled(bool enabled)
		{
			PlayerPrefs.SetInt("ELWS_IgnitionEnabled", enabled ? 1 : 0);
		}

		internal static bool GetIgnitionFeatureEnabled()
		{
			return PlayerPrefs.GetInt("ELWS_IgnitionFeatureEnabled", 1) != 0;
		}

		internal static void SetIgnitionFeatureEnabled(bool enabled)
		{
			PlayerPrefs.SetInt("ELWS_IgnitionFeatureEnabled", enabled ? 1 : 0);
		}

		internal static float GetIgnitionHoldSeconds()
		{
			return Mathf.Clamp(PlayerPrefs.GetFloat("ELWS_IgnitionHoldSeconds", 1.5f), 0.25f, 5f);
		}

		internal static void SetIgnitionHoldSeconds(float seconds)
		{
			PlayerPrefs.SetFloat("ELWS_IgnitionHoldSeconds", Mathf.Clamp(seconds, 0.25f, 5f));
		}

		internal static void ResetVehicleDefaults()
		{
			SetManualTransmissionEnabled(enabled: false);
			SetManualGearCount(5);
			SetIgnitionFeatureEnabled(enabled: true);
			SetIgnitionEnabled(enabled: true);
			SetIgnitionHoldSeconds(1.5f);
			SetIgnitionSfxEnabled(enabled: true);
			SetManualSpeedMultForward(1f);
			SetManualSpeedMultReverse(1f);
			SetHeadlightIntensityMult(1f);
			SetHeadlightRangeMult(1f);
			PlayerPrefs.Save();
		}

		internal static void ResetHudDefaults()
		{
			SetHudSpeedUnit(SpeedUnit.Kmh);
			SetHudShowSpeed(enabled: true);
			SetHudShowTach(enabled: true);
			SetHudShowGear(enabled: true);
			SetHudReadoutAnchor(HudReadoutAnchor.BottomLeft);
			PlayerPrefs.DeleteKey("ELWS_HudSpeedAnchor");
			PlayerPrefs.DeleteKey("ELWS_HudTachAnchor");
			PlayerPrefs.DeleteKey("ELWS_HudGearAnchor");
			PlayerPrefs.Save();
		}

		internal static bool GetIgnitionSfxEnabled()
		{
			return PlayerPrefs.GetInt("ELWS_IgnitionSfxEnabled", 1) != 0;
		}

		internal static void SetIgnitionSfxEnabled(bool enabled)
		{
			PlayerPrefs.SetInt("ELWS_IgnitionSfxEnabled", enabled ? 1 : 0);
		}

		internal static void ToggleIgnition()
		{
			SetIgnitionEnabled(!GetIgnitionEnabled());
		}

		internal static bool GetIgnitionEnabledEffective()
		{
			if (!GetIgnitionFeatureEnabled())
			{
				return true;
			}
			BindingInput binding = GetBinding(BindingLayer.Normal, ButtonBindAction.IgnitionToggle);
			BindingInput binding2 = GetBinding(BindingLayer.Modified, ButtonBindAction.IgnitionToggle);
			if (binding.Kind == BindingKind.None && binding2.Kind == BindingKind.None)
			{
				return true;
			}
			return GetIgnitionEnabled();
		}

		internal static float GetHeadlightIntensityMult()
		{
			return Mathf.Clamp(PlayerPrefs.GetFloat("ELWS_HeadlightIntensityMult", 1f), 0.1f, 3f);
		}

		internal static void SetHeadlightIntensityMult(float mult)
		{
			PlayerPrefs.SetFloat("ELWS_HeadlightIntensityMult", Mathf.Clamp(mult, 0.1f, 3f));
		}

		internal static float GetHeadlightRangeMult()
		{
			return Mathf.Clamp(PlayerPrefs.GetFloat("ELWS_HeadlightRangeMult", 1f), 0.1f, 3f);
		}

		internal static void SetHeadlightRangeMult(float mult)
		{
			PlayerPrefs.SetFloat("ELWS_HeadlightRangeMult", Mathf.Clamp(mult, 0.1f, 3f));
		}

		internal static HudReadoutAnchor GetHudReadoutAnchor()
		{
			return (HudReadoutAnchor)Mathf.Clamp(PlayerPrefs.GetInt("ELWS_HudReadoutAnchor", 0), 0, 1);
		}

		internal static HudReadoutAnchor GetHudSpeedAnchor()
		{
			if (!PlayerPrefs.HasKey("ELWS_HudSpeedAnchor"))
			{
				return GetHudReadoutAnchor();
			}
			return (HudReadoutAnchor)Mathf.Clamp(PlayerPrefs.GetInt("ELWS_HudSpeedAnchor", (int)GetHudReadoutAnchor()), 0, 1);
		}

		internal static void SetHudSpeedAnchor(HudReadoutAnchor anchor)
		{
			PlayerPrefs.SetInt("ELWS_HudSpeedAnchor", (int)anchor);
		}

		internal static HudReadoutAnchor GetHudTachAnchor()
		{
			if (!PlayerPrefs.HasKey("ELWS_HudTachAnchor"))
			{
				return GetHudReadoutAnchor();
			}
			return (HudReadoutAnchor)Mathf.Clamp(PlayerPrefs.GetInt("ELWS_HudTachAnchor", (int)GetHudReadoutAnchor()), 0, 1);
		}

		internal static void SetHudTachAnchor(HudReadoutAnchor anchor)
		{
			PlayerPrefs.SetInt("ELWS_HudTachAnchor", (int)anchor);
		}

		internal static HudReadoutAnchor GetHudGearAnchor()
		{
			if (!PlayerPrefs.HasKey("ELWS_HudGearAnchor"))
			{
				return GetHudReadoutAnchor();
			}
			return (HudReadoutAnchor)Mathf.Clamp(PlayerPrefs.GetInt("ELWS_HudGearAnchor", (int)GetHudReadoutAnchor()), 0, 1);
		}

		internal static void SetHudGearAnchor(HudReadoutAnchor anchor)
		{
			PlayerPrefs.SetInt("ELWS_HudGearAnchor", (int)anchor);
		}

		internal static void SetHudReadoutAnchor(HudReadoutAnchor anchor)
		{
			PlayerPrefs.SetInt("ELWS_HudReadoutAnchor", (int)anchor);
		}

		internal static HudReadoutAnchor NextHudReadoutAnchor(HudReadoutAnchor anchor)
		{
			if (anchor != 0)
			{
				return HudReadoutAnchor.BottomLeft;
			}
			return HudReadoutAnchor.BottomRight;
		}

		internal static string GetHudReadoutAnchorLabel(HudReadoutAnchor anchor)
		{
			if (anchor != HudReadoutAnchor.BottomRight)
			{
				return "Bottom L";
			}
			return "Bottom R";
		}

		internal static SpeedUnit GetHudSpeedUnit()
		{
			return (SpeedUnit)Mathf.Clamp(PlayerPrefs.GetInt("ELWS_HudSpeedUnits", 0), 0, 1);
		}

		internal static void SetHudSpeedUnit(SpeedUnit unit)
		{
			PlayerPrefs.SetInt("ELWS_HudSpeedUnits", (int)unit);
		}

		internal static SpeedUnit NextHudSpeedUnit(SpeedUnit unit)
		{
			if (unit != 0)
			{
				return SpeedUnit.Kmh;
			}
			return SpeedUnit.Mph;
		}

		internal static string GetHudSpeedUnitLabel(SpeedUnit unit)
		{
			if (unit != SpeedUnit.Mph)
			{
				return "km/h";
			}
			return "mph";
		}

		internal static float ConvertSpeedForHud(float kmh)
		{
			if (GetHudSpeedUnit() == SpeedUnit.Mph)
			{
				return kmh * 0.6213712f;
			}
			return kmh;
		}

		internal static bool GetHudShowTach()
		{
			return PlayerPrefs.GetInt("ELWS_HudShowTach", 1) != 0;
		}

		internal static void SetHudShowTach(bool enabled)
		{
			PlayerPrefs.SetInt("ELWS_HudShowTach", enabled ? 1 : 0);
		}

		internal static bool GetHudShowGear()
		{
			return PlayerPrefs.GetInt("ELWS_HudShowGear", 1) != 0;
		}

		internal static void SetHudShowGear(bool enabled)
		{
			PlayerPrefs.SetInt("ELWS_HudShowGear", enabled ? 1 : 0);
		}

		internal static void ToggleManualTransmission()
		{
			bool num = !GetManualTransmissionEnabled();
			SetManualTransmissionEnabled(num);
			if (num)
			{
				_manualGear = 1;
			}
		}

		internal static float GetManualSpeedMultForward()
		{
			return Mathf.Clamp(PlayerPrefs.GetFloat("ELWS_ManualSpeedMultFwd", 1f), 0.5f, 1.5f);
		}

		internal static void SetManualSpeedMultForward(float value)
		{
			PlayerPrefs.SetFloat("ELWS_ManualSpeedMultFwd", Mathf.Clamp(value, 0.5f, 1.5f));
		}

		internal static float GetManualSpeedMultReverse()
		{
			return Mathf.Clamp(PlayerPrefs.GetFloat("ELWS_ManualSpeedMultRev", 1f), 0.5f, 1.5f);
		}

		internal static void SetManualSpeedMultReverse(float value)
		{
			PlayerPrefs.SetFloat("ELWS_ManualSpeedMultRev", Mathf.Clamp(value, 0.5f, 1.5f));
		}

		internal static void ShiftManualGear(int delta)
		{
			_manualGear = Mathf.Clamp(_manualGear + delta, -1, GetManualGearCount());
		}

		private static float GetMaxSpeedForGearKmh(int gear)
		{
			int manualGearCount = GetManualGearCount();
			gear = Mathf.Clamp(gear, 1, manualGearCount);
			float num = Mathf.Pow(5f, 1f / (float)Mathf.Max(1, manualGearCount - 1));
			return 25f * Mathf.Pow(num, (float)(gear - 1));
		}

		private static float GetMaxSpeedForCurrentGearKmh()
		{
			int manualGear = _manualGear;
			if (manualGear == 0)
			{
				return 1f;
			}
			float maxSpeedForGearKmh = GetMaxSpeedForGearKmh(Mathf.Clamp(Mathf.Abs(manualGear), 1, GetManualGearCount()));
			return Mathf.Max(1f, maxSpeedForGearKmh);
		}

		internal static float GetEstimatedRpm()
		{
			float num;
			if (!GetManualTransmissionEnabled())
			{
				num = Mathf.Clamp01(_currentSpeedKmh / 140f);
				return Mathf.Lerp(900f, 6500f, num);
			}
			if (_manualGear == 0)
			{
				return Mathf.Lerp(900f, 6500f, _neutralRev01);
			}
			GetMaxSpeedForGearKmh(Mathf.Abs(_manualGear));
			num = Mathf.Clamp01(_currentSpeedKmh / GetMaxSpeedForCurrentGearKmh());
			return Mathf.Lerp(900f, 6500f, num);
		}

		internal static float GetEstimatedRpmNormForSound()
		{
			if (!GetManualTransmissionEnabled())
			{
				return Mathf.Clamp01(_currentSpeedKmh / 140f);
			}
			if (_manualGear == 0)
			{
				_neutralRev01 = Mathf.Lerp(_neutralRev01, Mathf.Clamp01(_lastThrottle01), Time.deltaTime * 8f);
				return Mathf.Clamp(_neutralRev01, 0f, 1.2f);
			}
			GetMaxSpeedForGearKmh(Mathf.Abs(_manualGear));
			return Mathf.Clamp(_currentSpeedKmh / GetMaxSpeedForCurrentGearKmh(), 0f, 1.2f);
		}

		internal static float ComputeManualAccel(float gas)
		{
			if (!GetManualTransmissionEnabled())
			{
				return gas;
			}
			if (_manualGear == 0)
			{
				return 0f;
			}
			float num = Mathf.Max(0f, _currentSpeedKmh);
			float maxSpeedForCurrentGearKmh = GetMaxSpeedForCurrentGearKmh();
			float num2 = Mathf.Clamp01(num / Mathf.Max(1f, maxSpeedForCurrentGearKmh));
			float num3 = Mathf.Pow(1f - num2, 0.55f);
			float num4 = Mathf.Lerp(0.55f, 1.2f, num3);
			float num5 = Mathf.Clamp01(gas) * num4;
			if (_manualGear >= 0)
			{
				return num5;
			}
			return 0f - num5;
		}

		private static bool ShouldApply()
		{
			return true;
		}

		internal static bool GetFfbEnabled()
		{
			return PlayerPrefs.GetInt("ELWS_FfbEnabled", 1) != 0;
		}

		internal static void SetFfbEnabled(bool enabled)
		{
			PlayerPrefs.SetInt("ELWS_FfbEnabled", enabled ? 1 : 0);
			if (!enabled)
			{
				StopAllForces();
			}
			ApplyControllerPropertiesIfReady();
		}

		internal static float GetFfbOverallGain()
		{
			return Mathf.Clamp01(PlayerPrefs.GetFloat("ELWS_FfbOverall", 0.55f));
		}

		internal static void SetFfbOverallGain(float value)
		{
			value = Mathf.Clamp01(value);
			PlayerPrefs.SetFloat("ELWS_FfbOverall", value);
			ApplyControllerPropertiesIfReady();
		}

		internal static float GetFfbSpringGain()
		{
			return Mathf.Clamp01(PlayerPrefs.GetFloat("ELWS_FfbSpring", 0.6f));
		}

		internal static void SetFfbSpringGain(float value)
		{
			value = Mathf.Clamp01(value);
			PlayerPrefs.SetFloat("ELWS_FfbSpring", value);
			ApplyControllerPropertiesIfReady();
		}

		internal static float GetFfbDamperGain()
		{
			return Mathf.Clamp01(PlayerPrefs.GetFloat("ELWS_FfbDamper", 0.2f));
		}

		internal static void SetFfbDamperGain(float value)
		{
			value = Mathf.Clamp01(value);
			PlayerPrefs.SetFloat("ELWS_FfbDamper", value);
			ApplyControllerPropertiesIfReady();
		}

		internal static int GetWheelRange()
		{
			return Mathf.Clamp(PlayerPrefs.GetInt("ELWS_WheelRange", 360), 180, 900);
		}

		internal static void SetWheelRange(int degrees)
		{
			degrees = Mathf.Clamp(degrees, 180, 900);
			PlayerPrefs.SetInt("ELWS_WheelRange", degrees);
			ApplyWheelRangeIfReady();
		}

		internal static float GetSteeringGain()
		{
			return Mathf.Clamp(PlayerPrefs.GetFloat("ELWS_SteerGain", 1f), 0.5f, 3f);
		}

		internal static void SetSteeringGain(float value)
		{
			value = Mathf.Clamp(value, 0.5f, 3f);
			PlayerPrefs.SetFloat("ELWS_SteerGain", value);
		}

		internal static void ResetFfbDefaults()
		{
			PlayerPrefs.SetInt("ELWS_FfbEnabled", 1);
			PlayerPrefs.SetFloat("ELWS_FfbOverall", 0.55f);
			PlayerPrefs.SetFloat("ELWS_FfbSpring", 0.6f);
			PlayerPrefs.SetFloat("ELWS_FfbDamper", 0.2f);
			StopAllForces();
			ApplyControllerPropertiesIfReady();
		}

		internal static void ResetSteeringDefaults()
		{
			PlayerPrefs.SetInt("ELWS_WheelRange", 360);
			PlayerPrefs.SetFloat("ELWS_SteerGain", 1f);
			PlayerPrefs.SetFloat("ELWS_SteerDeadzone", 0.01f);
			ApplyWheelRangeIfReady();
		}

		internal static float GetSteeringDeadzone()
		{
			return Mathf.Clamp(PlayerPrefs.GetFloat("ELWS_SteerDeadzone", 0.01f), 0f, 0.12f);
		}

		internal static void SetSteeringDeadzone(float value)
		{
			value = Mathf.Clamp(value, 0f, 0.12f);
			PlayerPrefs.SetFloat("ELWS_SteerDeadzone", value);
		}

		internal static AxisId GetSteeringAxis()
		{
			return (AxisId)Mathf.Clamp(PlayerPrefs.GetInt("ELWS_Axis_Steer", 0), 0, 7);
		}

		internal static void SetSteeringAxis(AxisId axis)
		{
			PlayerPrefs.SetInt("ELWS_Axis_Steer", (int)axis);
			PlayerPrefs.DeleteKey("ELWS_Cal_SteerCenter");
			PlayerPrefs.DeleteKey("ELWS_Cal_SteerLeft");
			PlayerPrefs.DeleteKey("ELWS_Cal_SteerRight");
		}

		internal static AxisId GetThrottleAxis()
		{
			return (AxisId)Mathf.Clamp(PlayerPrefs.GetInt("ELWS_Axis_Throttle", 1), 0, 7);
		}

		internal static AxisId GetBrakeAxis()
		{
			return (AxisId)Mathf.Clamp(PlayerPrefs.GetInt("ELWS_Axis_Brake", 5), 0, 7);
		}

		internal static AxisId GetClutchAxis()
		{
			return (AxisId)Mathf.Clamp(PlayerPrefs.GetInt("ELWS_Axis_Clutch", 4), 0, 7);
		}

		internal static void SetThrottleAxis(AxisId axis)
		{
			PlayerPrefs.SetInt("ELWS_Axis_Throttle", (int)axis);
			PlayerPrefs.DeleteKey("ELWS_Cal_ThrottleReleased");
			PlayerPrefs.DeleteKey("ELWS_Cal_ThrottlePressed");
		}

		internal static void SetBrakeAxis(AxisId axis)
		{
			PlayerPrefs.SetInt("ELWS_Axis_Brake", (int)axis);
			PlayerPrefs.DeleteKey("ELWS_Cal_BrakeReleased");
			PlayerPrefs.DeleteKey("ELWS_Cal_BrakePressed");
		}

		internal static void SetClutchAxis(AxisId axis)
		{
			PlayerPrefs.SetInt("ELWS_Axis_Clutch", (int)axis);
			PlayerPrefs.DeleteKey("ELWS_Cal_ClutchReleased");
			PlayerPrefs.DeleteKey("ELWS_Cal_ClutchPressed");
		}

		private static void DetectWheelOnce()
		{
			if (!ShouldApply())
			{
				return;
			}
			string[] joystickNames;
			try
			{
				joystickNames = Input.GetJoystickNames();
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("Failed to query joystick names: " + ex.GetType().Name + ": " + ex.Message));
				return;
			}
			if (joystickNames == null || joystickNames.Length == 0)
			{
				LogDebug("No joysticks detected by Unity.");
				return;
			}
			List<string> list = new List<string>();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < joystickNames.Length; i++)
			{
				string text = joystickNames[i];
				if (!string.IsNullOrWhiteSpace(text))
				{
					text = text.Trim();
					if (text.Length != 0 && hashSet.Add(text))
					{
						list.Add(text);
					}
				}
			}
			if (list.Count == 0)
			{
				LogDebug("No joysticks detected by Unity.");
			}
			else if (_logDetectedDevices != null && _logDetectedDevices.Value)
			{
				for (int j = 0; j < list.Count; j++)
				{
					_log.LogInfo((object)$"Joystick {j + 1}: '{list[j]}'");
				}
			}
		}

		private static void TryInitLogitech()
		{
			if (_logiAvailable || (_logiInitAttempted && Time.unscaledTime < _logiNextInitAttemptTime))
			{
				return;
			}
			_logiInitAttempted = true;
			_logiInitAttemptCount++;
			try
			{
				_logiIndex = 0;
				bool flag = _ignoreXInputControllers == null || _ignoreXInputControllers.Value;
				if (TryInitLogitechInternal(flag))
				{
					return;
				}
				if (TryInitLogitechInternal(!flag))
				{
					_log.LogInfo((object)$"Logitech SDK initialized with ignoreXInputControllers={!flag} fallback.");
					return;
				}
				if (_logiInitAttemptCount == 1)
				{
					_log.LogInfo((object)"Logitech SDK not ready yet; retrying...");
					_log.LogInfo((object)"If this never initializes, make sure Logitech G HUB/LGS is installed and the wheel is connected/powered.");
				}
				else if (_logiInitAttemptCount == 5)
				{
					_log.LogWarning((object)"Still retrying Logitech SDK init (wheel/G HUB may still be starting). You can also use 'Retry SDK' in wheel.exe.");
				}
				else
				{
					LogDebug($"Logitech SDK init still not ready (attempt {_logiInitAttemptCount}).");
				}
				_logiNextInitAttemptTime = Time.unscaledTime + 3f;
			}
			catch (DllNotFoundException ex)
			{
				_logiAvailable = false;
				_log.LogWarning((object)"Logitech SDK DLL not found (LogitechSteeringWheelEnginesWrapper.dll). FFB/input disabled.");
				LogDebug(ex.ToString());
				_logiNextInitAttemptTime = Time.unscaledTime + 10f;
			}
			catch (BadImageFormatException ex2)
			{
				_logiAvailable = false;
				_log.LogWarning((object)"Logitech SDK DLL is wrong architecture. FFB/input disabled.");
				LogDebug(ex2.ToString());
				_logiNextInitAttemptTime = Time.unscaledTime + 10f;
			}
			catch (Exception ex3)
			{
				_logiAvailable = false;
				_log.LogWarning((object)("Logitech SDK init threw " + ex3.GetType().Name + ". FFB/input disabled."));
				LogDebug(ex3.ToString());
				_logiNextInitAttemptTime = Time.unscaledTime + 10f;
			}
		}

		private static bool TryInitLogitechInternal(bool ignoreXInputControllers)
		{
			if (!LogitechGSDK.LogiSteeringInitialize(ignoreXInputControllers))
			{
				return false;
			}
			_logiIgnoreXInputUsed = ignoreXInputControllers;
			_logiAvailable = true;
			_log.LogMessage((object)$"Logitech SDK initialized (ignoreXInputControllers={ignoreXInputControllers}).");
			try
			{
				SafeLogiUpdate();
				SelectBestLogitechDeviceIndex();
			}
			catch
			{
			}
			ApplyControllerPropertiesIfReady();
			ApplyWheelRangeIfReady();
			return true;
		}

		private static void SelectBestLogitechDeviceIndex()
		{
			if (!_logiAvailable)
			{
				return;
			}
			_logiSelectionDone = true;
			_logiLastSelectionAttemptTime = Time.unscaledTime;
			List<LogiDeviceSnapshot> list = new List<LogiDeviceSnapshot>(4);
			for (int i = 0; i < 4; i++)
			{
				bool flag;
				try
				{
					flag = LogitechGSDK.LogiIsConnected(i);
				}
				catch
				{
					continue;
				}
				if (flag)
				{
					LogiDeviceSnapshot logiDeviceSnapshot = default(LogiDeviceSnapshot);
					logiDeviceSnapshot.Index = i;
					logiDeviceSnapshot.Connected = true;
					logiDeviceSnapshot.Name = TryGetWheelFriendlyName(i);
					logiDeviceSnapshot.Path = TryGetWheelDevicePath(i);
					LogiDeviceSnapshot item = logiDeviceSnapshot;
					TryExtractVidPid(item.Path, out item.Vid, out item.Pid);
					try
					{
						item.IsWheel = LogitechGSDK.LogiIsDeviceConnected(i, 0);
					}
					catch
					{
					}
					try
					{
						item.IsGamepad = LogitechGSDK.LogiIsDeviceConnected(i, 2);
					}
					catch
					{
					}
					try
					{
						item.IsJoystick = LogitechGSDK.LogiIsDeviceConnected(i, 1);
					}
					catch
					{
					}
					try
					{
						item.IsLogitech = LogitechGSDK.LogiIsManufacturerConnected(i, 0);
					}
					catch
					{
					}
					try
					{
						item.IsG920 = LogitechGSDK.LogiIsModelConnected(i, 27);
					}
					catch
					{
					}
					try
					{
						item.IsG29 = LogitechGSDK.LogiIsModelConnected(i, 26);
					}
					catch
					{
					}
					list.Add(item);
				}
			}
			if (list.Count <= 0)
			{
				return;
			}
			int num = _logiIndex;
			int num2 = int.MinValue;
			for (int j = 0; j < list.Count; j++)
			{
				LogiDeviceSnapshot logiDeviceSnapshot2 = list[j];
				int num3 = 0;
				if (logiDeviceSnapshot2.IsWheel)
				{
					num3 += 100;
				}
				if (logiDeviceSnapshot2.IsLogitech)
				{
					num3 += 20;
				}
				if (logiDeviceSnapshot2.IsG920)
				{
					num3 += 50;
				}
				if (logiDeviceSnapshot2.IsG29)
				{
					num3 += 40;
				}
				if (logiDeviceSnapshot2.IsGamepad)
				{
					num3 -= 100;
				}
				if (logiDeviceSnapshot2.IsJoystick && !logiDeviceSnapshot2.IsWheel)
				{
					num3 -= 20;
				}
				if (logiDeviceSnapshot2.Vid == 1133)
				{
					num3 += 10;
				}
				if (num3 > num2)
				{
					num2 = num3;
					num = logiDeviceSnapshot2.Index;
				}
			}
			if (num != _logiIndex)
			{
				_logiIndex = num;
				if (_log != null)
				{
					_log.LogInfo((object)$"Selected Logitech device index {_logiIndex} (preferred wheel device). ");
				}
			}
			if (_log == null || _logiWarnedSelectedNotWheel)
			{
				return;
			}
			for (int k = 0; k < list.Count; k++)
			{
				if (list[k].Index == _logiIndex)
				{
					if (!list[k].IsWheel)
					{
						_log.LogWarning((object)"Selected Logitech SDK device is not a wheel. If you have a wheel connected, unplug other controllers and retry SDK.");
						_logiWarnedSelectedNotWheel = true;
					}
					break;
				}
			}
		}

		private static bool TryExtractVidPid(string devicePath, out int vid, out int pid)
		{
			vid = 0;
			pid = 0;
			if (string.IsNullOrWhiteSpace(devicePath))
			{
				return false;
			}
			int num = devicePath.IndexOf("vid_", StringComparison.OrdinalIgnoreCase);
			int num2 = devicePath.IndexOf("pid_", StringComparison.OrdinalIgnoreCase);
			if (num < 0 || num2 < 0)
			{
				return false;
			}
			string text = SafeHexSlice(devicePath, num + 4, 4);
			string text2 = SafeHexSlice(devicePath, num2 + 4, 4);
			if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(text2))
			{
				return false;
			}
			if (!int.TryParse(text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out vid))
			{
				vid = 0;
				return false;
			}
			if (!int.TryParse(text2, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out pid))
			{
				vid = 0;
				pid = 0;
				return false;
			}
			return true;
		}

		private static string SafeHexSlice(string s, int start, int maxLen)
		{
			if (string.IsNullOrEmpty(s) || start < 0 || start >= s.Length || maxLen <= 0)
			{
				return null;
			}
			int num = Math.Min(maxLen, s.Length - start);
			int num2 = start;
			for (int i = 0; i < num; i++)
			{
				char c = s[start + i];
				if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F'))
				{
					break;
				}
				num2++;
			}
			int num3 = num2 - start;
			if (num3 <= 0)
			{
				return null;
			}
			return s.Substring(start, num3);
		}

		internal static void ForceReinitLogitech()
		{
			ForceReinitLogitech(forceReconnect: false);
		}

		internal static void ForceReinitLogitech(bool forceReconnect)
		{
			try
			{
				if (_logiAvailable)
				{
					SafeLogiUpdate();
					_logiConnected = LogitechGSDK.LogiIsConnected(_logiIndex);
				}
			}
			catch
			{
			}
			if (!forceReconnect && _logiAvailable && _logiConnected)
			{
				ApplyControllerPropertiesIfReady();
				ApplyWheelRangeIfReady();
				return;
			}
			if (forceReconnect && _log != null)
			{
				_log.LogInfo((object)"Forcing Logitech SDK reconnect...");
			}
			_logiAvailable = false;
			_logiConnected = false;
			_logiInitAttempted = false;
			_logiInitAttemptCount = 0;
			_logiNextInitAttemptTime = 0f;
			try
			{
				StopAllForces();
				LogitechGSDK.LogiSteeringShutdown();
			}
			catch
			{
			}
			_logiWasConnected = false;
			_logiLastName = null;
			_logiLastPath = null;
			_logiSelectionDone = false;
			_logiLastSelectionAttemptTime = 0f;
			_logiWarnedSelectedNotWheel = false;
			TryInitLogitech();
		}

		internal static string GetLogitechStatus()
		{
			if (!_logiInitAttempted)
			{
				return "Not initialized";
			}
			if (!_logiAvailable)
			{
				return "Retrying";
			}
			if (!_logiConnected)
			{
				return "No wheel";
			}
			return "Connected";
		}

		private static void MaybeLogWheelDetected()
		{
			if (_log == null)
			{
				return;
			}
			if (!_logiConnected)
			{
				_logiWasConnected = false;
				return;
			}
			string text = TryGetWheelFriendlyName(_logiIndex);
			string text2 = TryGetWheelDevicePath(_logiIndex);
			bool num = !_logiWasConnected || (!string.IsNullOrWhiteSpace(text) && !string.Equals(text, _logiLastName, StringComparison.Ordinal)) || (!string.IsNullOrWhiteSpace(text2) && !string.Equals(text2, _logiLastPath, StringComparison.Ordinal));
			_logiWasConnected = true;
			if (!string.IsNullOrWhiteSpace(text))
			{
				_logiLastName = text;
			}
			if (!string.IsNullOrWhiteSpace(text2))
			{
				_logiLastPath = text2;
			}
			if (!num)
			{
				return;
			}
			if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(text2))
			{
				_log.LogMessage((object)("Wheel detected: " + text + " (" + text2 + ")"));
				return;
			}
			if (!string.IsNullOrWhiteSpace(text))
			{
				_log.LogMessage((object)("Wheel detected: " + text));
				return;
			}
			if (!string.IsNullOrWhiteSpace(text2))
			{
				_log.LogMessage((object)("Wheel detected: " + text2));
				return;
			}
			try
			{
				if (LogitechGSDK.LogiIsModelConnected(_logiIndex, 27))
				{
					_log.LogMessage((object)"Wheel detected: Logitech G920");
				}
				else if (LogitechGSDK.LogiIsModelConnected(_logiIndex, 26))
				{
					_log.LogMessage((object)"Wheel detected: Logitech G29");
				}
				else
				{
					_log.LogMessage((object)"Wheel detected.");
				}
			}
			catch
			{
				_log.LogMessage((object)"Wheel detected.");
			}
		}

		private static string TryGetWheelFriendlyName(int index)
		{
			try
			{
				StringBuilder stringBuilder = new StringBuilder(256);
				if (LogitechGSDK.LogiGetFriendlyProductName(index, stringBuilder, stringBuilder.Capacity))
				{
					string text = stringBuilder.ToString();
					return string.IsNullOrWhiteSpace(text) ? null : text.Trim();
				}
			}
			catch
			{
			}
			return null;
		}

		private static string TryGetWheelDevicePath(int index)
		{
			try
			{
				StringBuilder stringBuilder = new StringBuilder(512);
				if (LogitechGSDK.LogiGetDevicePath(index, stringBuilder, stringBuilder.Capacity))
				{
					string text = stringBuilder.ToString();
					return string.IsNullOrWhiteSpace(text) ? null : text.Trim();
				}
			}
			catch
			{
			}
			return null;
		}

		internal static void SetWheelLastInput(float steer, float accel)
		{
			_wheelLastUpdateFrame = Time.frameCount;
			_wheelLastUpdateTime = Time.unscaledTime;
			_wheelLastSteer = Mathf.Clamp(steer, -1f, 1f);
			_wheelLastAccel = Mathf.Clamp(accel, -1f, 1f);
		}

		internal static bool TryGetWheelLastInput(out float steer, out float accel)
		{
			steer = 0f;
			accel = 0f;
			if (Time.frameCount != _wheelLastUpdateFrame)
			{
				return false;
			}
			steer = _wheelLastSteer;
			accel = _wheelLastAccel;
			return true;
		}

		internal static bool TryGetWheelLastInputRecent(float maxAgeSeconds, out float steer, out float accel)
		{
			steer = 0f;
			accel = 0f;
			if (Time.unscaledTime - _wheelLastUpdateTime > maxAgeSeconds)
			{
				return false;
			}
			steer = _wheelLastSteer;
			accel = _wheelLastAccel;
			return true;
		}

		internal static void SetWheelMenuActive(bool active)
		{
			if (active)
			{
				_wheelMenuHeartbeatTime = Time.unscaledTime;
			}
		}

		internal static void SetBindingCaptureActive(bool active)
		{
			if (active)
			{
				_bindingCaptureHeartbeatTime = Time.unscaledTime;
			}
		}

		internal static void SetCalibrationWizardActive(bool active)
		{
			if (active)
			{
				_calibrationWizardHeartbeatTime = Time.unscaledTime;
			}
		}

		internal static void SetFfbPageActive(bool active)
		{
			if (active)
			{
				_ffbPageHeartbeatTime = Time.unscaledTime;
				ApplyControllerPropertiesIfReady(true);
			}
			else
			{
				ApplyControllerPropertiesIfReady(null);
			}
		}

		private static bool IsWheelMenuActive()
		{
			return Time.unscaledTime - _wheelMenuHeartbeatTime < 0.5f;
		}

		private static bool IsFfbPageActive()
		{
			return Time.unscaledTime - _ffbPageHeartbeatTime < 0.5f;
		}

		internal static bool IsBindingCaptureActive()
		{
			return Time.unscaledTime - _bindingCaptureHeartbeatTime < 0.5f;
		}

		internal static bool IsCalibrationWizardActive()
		{
			return Time.unscaledTime - _calibrationWizardHeartbeatTime < 0.5f;
		}

		internal static bool TryGetLogiState(out LogitechGSDK.DIJOYSTATE2ENGINES state)
		{
			state = default(LogitechGSDK.DIJOYSTATE2ENGINES);
			if (!ShouldApply())
			{
				return false;
			}
			if (!_logiInitAttempted)
			{
				TryInitLogitech();
			}
			if (!_logiAvailable)
			{
				return false;
			}
			if (!SafeLogiUpdate())
			{
				return false;
			}
			if (!_logiSelectionDone || Time.unscaledTime - _logiLastSelectionAttemptTime > 2f)
			{
				bool flag = false;
				try
				{
					flag = LogitechGSDK.LogiIsDeviceConnected(_logiIndex, 0);
				}
				catch
				{
				}
				if (!flag)
				{
					try
					{
						SelectBestLogitechDeviceIndex();
					}
					catch
					{
					}
				}
			}
			_logiConnected = LogitechGSDK.LogiIsConnected(_logiIndex);
			if (!_logiConnected)
			{
				_logiWasConnected = false;
				return false;
			}
			MaybeLogWheelDetected();
			state = LogitechGSDK.LogiGetStateCSharp(_logiIndex);
			EnsureDefaultCalibrationFromState(state);
			return true;
		}

		private static void EnsureDefaultCalibrationFromState(LogitechGSDK.DIJOYSTATE2ENGINES state)
		{
			int axisValue = GetAxisValue(state, GetThrottleAxis());
			if (!PlayerPrefs.HasKey("ELWS_Cal_ThrottleReleased"))
			{
				PlayerPrefs.SetInt("ELWS_Cal_ThrottleReleased", axisValue);
			}
			if (!PlayerPrefs.HasKey("ELWS_Cal_ThrottlePressed"))
			{
				PlayerPrefs.SetInt("ELWS_Cal_ThrottlePressed", GuessPressedFromReleased(PlayerPrefs.GetInt("ELWS_Cal_ThrottleReleased")));
			}
			int axisValue2 = GetAxisValue(state, GetBrakeAxis());
			if (!PlayerPrefs.HasKey("ELWS_Cal_BrakeReleased"))
			{
				PlayerPrefs.SetInt("ELWS_Cal_BrakeReleased", axisValue2);
			}
			if (!PlayerPrefs.HasKey("ELWS_Cal_BrakePressed"))
			{
				PlayerPrefs.SetInt("ELWS_Cal_BrakePressed", GuessPressedFromReleased(PlayerPrefs.GetInt("ELWS_Cal_BrakeReleased")));
			}
			int axisValue3 = GetAxisValue(state, GetClutchAxis());
			if (!PlayerPrefs.HasKey("ELWS_Cal_ClutchReleased"))
			{
				PlayerPrefs.SetInt("ELWS_Cal_ClutchReleased", axisValue3);
			}
			if (!PlayerPrefs.HasKey("ELWS_Cal_ClutchPressed"))
			{
				PlayerPrefs.SetInt("ELWS_Cal_ClutchPressed", GuessPressedFromReleased(PlayerPrefs.GetInt("ELWS_Cal_ClutchReleased")));
			}
			if (!PlayerPrefs.HasKey("ELWS_Cal_SteerCenter"))
			{
				PlayerPrefs.SetInt("ELWS_Cal_SteerCenter", state.lX);
			}
			if (!PlayerPrefs.HasKey("ELWS_Cal_SteerLeft"))
			{
				PlayerPrefs.SetInt("ELWS_Cal_SteerLeft", -32768);
			}
			if (!PlayerPrefs.HasKey("ELWS_Cal_SteerRight"))
			{
				PlayerPrefs.SetInt("ELWS_Cal_SteerRight", 32767);
			}
		}

		private static int GuessPressedFromReleased(int released)
		{
			if (released >= 16000)
			{
				return -32768;
			}
			if (released <= -16000)
			{
				return 32767;
			}
			return -32768;
		}

		internal static bool HasCalibration()
		{
			if (PlayerPrefs.HasKey("ELWS_Cal_SteerLeft") && PlayerPrefs.HasKey("ELWS_Cal_SteerRight") && PlayerPrefs.HasKey("ELWS_Cal_ThrottleReleased") && PlayerPrefs.HasKey("ELWS_Cal_ThrottlePressed") && PlayerPrefs.HasKey("ELWS_Cal_BrakeReleased"))
			{
				return PlayerPrefs.HasKey("ELWS_Cal_BrakePressed");
			}
			return false;
		}

		internal static void RequestOpenCalibrationWizard()
		{
			_openCalibrationWizardRequested = true;
		}

		internal static bool ConsumeOpenCalibrationWizardRequest()
		{
			bool openCalibrationWizardRequested = _openCalibrationWizardRequested;
			_openCalibrationWizardRequested = false;
			return openCalibrationWizardRequested;
		}

		internal static void RequestOpenAxisMapping()
		{
			_openAxisMappingRequested = true;
		}

		internal static bool ConsumeOpenAxisMappingRequest()
		{
			bool openAxisMappingRequested = _openAxisMappingRequested;
			_openAxisMappingRequested = false;
			return openAxisMappingRequested;
		}

		internal static void ClearCalibration()
		{
			PlayerPrefs.DeleteKey("ELWS_Cal_SteerCenter");
			PlayerPrefs.DeleteKey("ELWS_Cal_SteerLeft");
			PlayerPrefs.DeleteKey("ELWS_Cal_SteerRight");
			PlayerPrefs.DeleteKey("ELWS_Cal_ThrottleReleased");
			PlayerPrefs.DeleteKey("ELWS_Cal_ThrottlePressed");
			PlayerPrefs.DeleteKey("ELWS_Cal_BrakeReleased");
			PlayerPrefs.DeleteKey("ELWS_Cal_BrakePressed");
			PlayerPrefs.DeleteKey("ELWS_Cal_ClutchReleased");
			PlayerPrefs.DeleteKey("ELWS_Cal_ClutchPressed");
		}

		internal static float NormalizeSteering(int rawX)
		{
			int @int = PlayerPrefs.GetInt("ELWS_Cal_SteerLeft", -32768);
			int int2 = PlayerPrefs.GetInt("ELWS_Cal_SteerRight", 32767);
			int int3 = PlayerPrefs.GetInt("ELWS_Cal_SteerCenter", (@int + int2) / 2);
			if (int2 == @int)
			{
				return 0f;
			}
			float num2;
			if (rawX >= int3)
			{
				float num = int2 - int3;
				num2 = ((num <= 0.001f) ? 0f : ((float)(rawX - int3) / num));
			}
			else
			{
				float num3 = int3 - @int;
				num2 = ((num3 <= 0.001f) ? 0f : ((float)(-(int3 - rawX)) / num3));
			}
			num2 = Mathf.Clamp(num2, -1f, 1f);
			float steeringDeadzone = GetSteeringDeadzone();
			float num4 = Mathf.Abs(num2);
			num2 = ((!(num4 <= steeringDeadzone)) ? (Mathf.Sign(num2) * Mathf.Clamp01((num4 - steeringDeadzone) / Mathf.Max(0.0001f, 1f - steeringDeadzone))) : 0f);
			float steeringGain = GetSteeringGain();
			return Mathf.Clamp(num2 * steeringGain, -1f, 1f);
		}

		internal static float NormalizePedal(int rawAxis, PedalKind kind)
		{
			string text;
			string text2;
			switch (kind)
			{
			case PedalKind.Throttle:
				text = "ELWS_Cal_ThrottleReleased";
				text2 = "ELWS_Cal_ThrottlePressed";
				break;
			case PedalKind.Brake:
				text = "ELWS_Cal_BrakeReleased";
				text2 = "ELWS_Cal_BrakePressed";
				break;
			default:
				text = "ELWS_Cal_ClutchReleased";
				text2 = "ELWS_Cal_ClutchPressed";
				break;
			}
			int @int = PlayerPrefs.GetInt(text, 32767);
			int int2 = PlayerPrefs.GetInt(text2, -32768);
			float num = Mathf.InverseLerp((float)@int, (float)int2, (float)rawAxis);
			num = Mathf.Clamp01(num);
			if (num < 0.05f)
			{
				num = 0f;
			}
			return num;
		}

		internal static int GetAxisValue(LogitechGSDK.DIJOYSTATE2ENGINES state, AxisId axis)
		{
			switch (axis)
			{
			case AxisId.lX:
				return state.lX;
			case AxisId.lY:
				return state.lY;
			case AxisId.lZ:
				return state.lZ;
			case AxisId.lRx:
				return state.lRx;
			case AxisId.lRy:
				return state.lRy;
			case AxisId.lRz:
				return state.lRz;
			case AxisId.slider0:
				if (state.rglSlider == null || state.rglSlider.Length == 0)
				{
					return 0;
				}
				return state.rglSlider[0];
			case AxisId.slider1:
				if (state.rglSlider == null || state.rglSlider.Length <= 1)
				{
					return 0;
				}
				return state.rglSlider[1];
			default:
				return 0;
			}
		}

		private static void ShutdownLogitech()
		{
			if (!_logiAvailable)
			{
				return;
			}
			try
			{
				StopAllForces();
				LogitechGSDK.LogiSteeringShutdown();
			}
			catch
			{
			}
		}

		internal static void StartFfbTest(FfbTestEffect effect, float durationSeconds = 2.5f)
		{
			if (effect == FfbTestEffect.None)
			{
				StopFfbTest();
				return;
			}
			_ffbTestEffect = effect;
			_ffbTestEndTime = Time.unscaledTime + Mathf.Clamp(durationSeconds, 0.25f, 10f);
			LogDebug("FFB test start: " + effect);
		}

		internal static void StopFfbTest()
		{
			if (_ffbTestEffect != 0)
			{
				LogDebug("FFB test stop");
			}
			_ffbTestEffect = FfbTestEffect.None;
			_ffbTestEndTime = 0f;
			StopAllForces();
		}

		internal static bool IsFfbTestActive()
		{
			if (_ffbTestEffect == FfbTestEffect.None)
			{
				return false;
			}
			if (Time.unscaledTime < _ffbTestEndTime)
			{
				return true;
			}
			_ffbTestEffect = FfbTestEffect.None;
			_ffbTestEndTime = 0f;
			return false;
		}

		private static void UpdateFfb()
		{
			if (!ShouldApply())
			{
				return;
			}
			TryInitLogitech();
			if (!_logiAvailable)
			{
				return;
			}
			bool flag = IsWheelMenuActive();
			bool flag2 = IsFfbPageActive();
			if (!flag2 && !GetFfbEnabled())
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime < _ffbNextUpdateTime)
			{
				return;
			}
			_ffbNextUpdateTime = unscaledTime + 1f / 120f;
			if ((PauseSystem.paused || IsInputLocked()) && (!flag || !GetFfbEnabled()) && !flag2)
			{
				StopAllForces();
			}
			else if (_isInWalkingMode && (!flag || !GetFfbEnabled()) && !flag2)
			{
				StopAllForces();
			}
			else
			{
				if (!SafeLogiUpdate())
				{
					return;
				}
				_logiConnected = LogitechGSDK.LogiIsConnected(_logiIndex);
				if (!_logiConnected)
				{
					_logiWasConnected = false;
					return;
				}
				MaybeLogWheelDetected();
				if (!LogitechGSDK.LogiHasForceFeedback(_logiIndex))
				{
					return;
				}
				bool flag3 = flag2 || (flag && GetFfbEnabled());
				float num = (flag3 ? 0f : Mathf.Clamp(_currentSpeedKmh, 0f, 200f));
				int num2 = Mathf.RoundToInt(Mathf.Lerp(5f, 35f, Mathf.Clamp01(num / 120f)) * GetFfbDamperGain());
				num2 = Mathf.Clamp(num2, 0, 100);
				if (num2 != _ffbLastDamper)
				{
					_ffbLastDamper = num2;
					LogitechGSDK.LogiPlayDamperForce(_logiIndex, num2);
				}
				int num3 = Mathf.RoundToInt(Mathf.Lerp(20f, 95f, Mathf.Clamp01(num / 100f)) * GetFfbSpringGain());
				num3 = Mathf.Clamp(num3, 0, 100);
				if (num3 != _ffbLastSpring)
				{
					_ffbLastSpring = num3;
					LogitechGSDK.LogiPlaySpringForce(_logiIndex, 0, num3, num3);
				}
				if (IsFfbTestActive())
				{
					LogitechGSDK.LogiStopDirtRoadEffect(_logiIndex);
					LogitechGSDK.LogiStopBumpyRoadEffect(_logiIndex);
					if (_ffbTestEffect == FfbTestEffect.Shake)
					{
						int num4 = Mathf.RoundToInt(Mathf.Sin(Time.unscaledTime * 14f) * 70f);
						num4 = Mathf.Clamp(num4, -100, 100);
						LogitechGSDK.LogiPlayConstantForce(_logiIndex, num4);
					}
					else if (_ffbTestEffect == FfbTestEffect.Bumpy)
					{
						LogitechGSDK.LogiStopConstantForce(_logiIndex);
						LogitechGSDK.LogiPlayBumpyRoadEffect(_logiIndex, 25);
					}
				}
				else if (!flag3 && _isOffRoad && num > 5f)
				{
					int num5 = Mathf.RoundToInt(Mathf.Lerp(10f, 35f, Mathf.Clamp01(num / 70f)));
					num5 = Mathf.Clamp(num5, 0, 100);
					if (num5 != _ffbLastDirt)
					{
						_ffbLastDirt = num5;
						_ffbLastBumpy = 0;
						LogitechGSDK.LogiPlayDirtRoadEffect(_logiIndex, num5);
						LogitechGSDK.LogiStopBumpyRoadEffect(_logiIndex);
					}
				}
				else if (!flag3 && _isSliding)
				{
					if (8 != _ffbLastBumpy)
					{
						_ffbLastBumpy = 8;
						_ffbLastDirt = 0;
						LogitechGSDK.LogiPlayBumpyRoadEffect(_logiIndex, 8);
						LogitechGSDK.LogiStopDirtRoadEffect(_logiIndex);
					}
				}
				else
				{
					if (_ffbLastDirt != 0)
					{
						_ffbLastDirt = 0;
						LogitechGSDK.LogiStopDirtRoadEffect(_logiIndex);
					}
					if (_ffbLastBumpy != 0)
					{
						_ffbLastBumpy = 0;
						LogitechGSDK.LogiStopBumpyRoadEffect(_logiIndex);
					}
				}
			}
		}

		private static bool IsInputLocked()
		{
			try
			{
				sInputManager[] players = sInputManager.players;
				if (players == null || players.Length == 0 || (Object)(object)players[0] == (Object)null)
				{
					return false;
				}
				return players[0].lockInput || players[0].freeCamMode;
			}
			catch
			{
				return false;
			}
		}

		private static bool SafeLogiUpdate()
		{
			try
			{
				return LogitechGSDK.LogiUpdate();
			}
			catch
			{
				return false;
			}
		}

		private static void StopAllForces()
		{
			if (!_logiAvailable)
			{
				return;
			}
			try
			{
				_ffbLastDamper = int.MinValue;
				_ffbLastSpring = int.MinValue;
				_ffbLastDirt = int.MinValue;
				_ffbLastBumpy = int.MinValue;
				LogitechGSDK.LogiStopSpringForce(_logiIndex);
				LogitechGSDK.LogiStopDamperForce(_logiIndex);
				LogitechGSDK.LogiStopDirtRoadEffect(_logiIndex);
				LogitechGSDK.LogiStopBumpyRoadEffect(_logiIndex);
				LogitechGSDK.LogiStopConstantForce(_logiIndex);
				LogitechGSDK.LogiStopSurfaceEffect(_logiIndex);
			}
			catch
			{
			}
		}

		private static void ApplyControllerPropertiesIfReady(bool? forceEnableOverride)
		{
			if (!_logiAvailable)
			{
				return;
			}
			try
			{
				bool forceEnable = (forceEnableOverride.HasValue ? forceEnableOverride.Value : GetFfbEnabled());
				LogitechGSDK.LogiControllerPropertiesData properties = default(LogitechGSDK.LogiControllerPropertiesData);
				properties.forceEnable = forceEnable;
				properties.overallGain = Mathf.RoundToInt(GetFfbOverallGain() * 100f);
				properties.springGain = Mathf.RoundToInt(GetFfbSpringGain() * 100f);
				properties.damperGain = Mathf.RoundToInt(GetFfbDamperGain() * 100f);
				properties.defaultSpringEnabled = false;
				properties.defaultSpringGain = 0;
				properties.combinePedals = false;
				properties.wheelRange = GetWheelRange();
				properties.gameSettingsEnabled = true;
				properties.allowGameSettings = true;
				LogitechGSDK.LogiSetPreferredControllerProperties(properties);
			}
			catch
			{
			}
		}

		private static void ApplyControllerPropertiesIfReady()
		{
			ApplyControllerPropertiesIfReady(null);
		}

		private static void ApplyWheelRangeIfReady()
		{
			if (!_logiAvailable)
			{
				return;
			}
			try
			{
				LogitechGSDK.LogiSetOperatingRange(_logiIndex, GetWheelRange());
			}
			catch
			{
			}
		}

		internal static void LogDebug(string message)
		{
			if (_debugLogging != null && _debugLogging.Value && _log != null)
			{
				_log.LogInfo((object)("[debug] " + message));
			}
		}

		private void Awake()
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_00ba: Expected O, but got Unknown
			_log = ((BaseUnityPlugin)this).Logger;
			_instance = this;
			MigrateConfigIfNeeded("shibe.easydeliveryco.logiwheel", "shibe.easydeliveryco.seblogiwheel");
			_logDetectedDevices = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "log_detected_devices", true, "Log joystick names detected by Unity on startup.");
			_debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "debug_logging", false, "Log debug information.");
			_ignoreXInputControllers = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ignore_xinput_controllers", true, "Pass 'ignoreXInputControllers' to the Logitech SDK init (recommended).");
			MigratePrefsFromG920IfNeeded();
			Harmony val = new Harmony("shibe.easydeliveryco.seblogiwheel");
			PatchByName(val, "sCarController", "Update", "SCarController_Update_Prefix");
			PatchByName(val, "sInputManager", "GetInput", null, "SInputManager_GetInput_Postfix");
			DetectWheelOnce();
			TryInitLogitech();
			_log.LogInfo((object)"SebLogiWheel loaded.");
		}

		private static void MigrateConfigIfNeeded(string oldGuid, string newGuid)
		{
			try
			{
				if (!string.IsNullOrWhiteSpace(oldGuid) && !string.IsNullOrWhiteSpace(newGuid) && !string.Equals(oldGuid, newGuid, StringComparison.OrdinalIgnoreCase))
				{
					string configPath = Paths.ConfigPath;
					string text = Path.Combine(configPath, oldGuid + ".cfg");
					string text2 = Path.Combine(configPath, newGuid + ".cfg");
					if (File.Exists(text) && !File.Exists(text2))
					{
						File.Copy(text, text2);
					}
				}
			}
			catch
			{
			}
		}

		private static void TryLoadIgnitionSfx()
		{
		}

		private static Object LoadWavOrNull(string path)
		{
			if (string.IsNullOrWhiteSpace(path))
			{
				return null;
			}
			if (Path.GetExtension(path).ToLowerInvariant() != ".wav")
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Ignition SFX: only .wav is supported in this build: " + path));
				}
				return null;
			}
			try
			{
				return WavToAudioClip(path);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Ignition SFX load failed: " + path + " (" + ex.Message + ")"));
				}
				return null;
			}
		}

		private static Object WavToAudioClip(string path)
		{
			byte[] array = File.ReadAllBytes(path);
			if (array.Length < 44)
			{
				throw new Exception("WAV too small");
			}
			if (ReadAscii(array, 0, 4) != "RIFF" || ReadAscii(array, 8, 4) != "WAVE")
			{
				throw new Exception("Not a RIFF/WAVE file");
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = -1;
			int num6 = 0;
			int num7 = -1;
			int num8 = 0;
			int num9 = 12;
			while (num9 + 8 <= array.Length)
			{
				string text = ReadAscii(array, num9, 4);
				int num10 = BitConverter.ToInt32(array, num9 + 4);
				int num11 = num9 + 8;
				if (num11 + num10 > array.Length)
				{
					break;
				}
				if (text == "fmt ")
				{
					num7 = num11;
					num8 = num10;
					num4 = BitConverter.ToInt16(array, num11);
					num = BitConverter.ToInt16(array, num11 + 2);
					num2 = BitConverter.ToInt32(array, num11 + 4);
					num3 = BitConverter.ToInt16(array, num11 + 14);
				}
				else if (text == "data")
				{
					num5 = num11;
					num6 = num10;
					break;
				}
				num9 = num11 + num10;
				if ((num9 & 1) == 1)
				{
					num9++;
				}
			}
			if (num5 < 0 || num6 <= 0)
			{
				throw new Exception("Missing data chunk");
			}
			if (_debugLogging != null && _debugLogging.Value)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)("Ignition SFX WAV: fmt=" + num4 + " bits=" + num3 + " ch=" + num + " hz=" + num2 + " data=" + num6 + " bytes (" + Path.GetFileName(path) + ")"));
				}
			}
			if (num4 == 65534)
			{
				if (num7 < 0 || num8 < 40)
				{
					throw new Exception("WAV extensible missing extended fmt");
				}
				short num12 = BitConverter.ToInt16(array, num7 + 16);
				int num13 = num7 + 24;
				if (num12 < 22 || num13 + 16 > num7 + num8)
				{
					throw new Exception("WAV extensible bad cbSize");
				}
				bool flag = GuidEquals(array, num13, new byte[16]
				{
					1, 0, 0, 0, 0, 0, 16, 0, 128, 0,
					0, 170, 0, 56, 155, 113
				});
				bool flag2 = GuidEquals(array, num13, new byte[16]
				{
					3, 0, 0, 0, 0, 0, 16, 0, 128, 0,
					0, 170, 0, 56, 155, 113
				});
				if (flag)
				{
					num4 = 1;
				}
				else
				{
					if (!flag2)
					{
						throw new Exception("Unsupported WAV extensible subformat");
					}
					num4 = 3;
				}
			}
			if (num4 != 1 && num4 != 3)
			{
				throw new Exception("Unsupported WAV format (need PCM/IEEE float)");
			}
			if (num != 1 && num != 2)
			{
				throw new Exception("Unsupported channel count: " + num);
			}
			if (num2 <= 0)
			{
				throw new Exception("Invalid sample rate");
			}
			if (num4 == 1)
			{
				if (num3 != 8 && num3 != 16 && num3 != 24 && num3 != 32)
				{
					throw new Exception("Unsupported PCM bit depth: " + num3);
				}
			}
			else if (num3 != 32)
			{
				throw new Exception("Unsupported float bit depth: " + num3);
			}
			int num14 = num3 / 8;
			float[] array2 = new float[num6 / num14];
			int num15 = 0;
			int num16 = Math.Min(array.Length, num5 + num6);
			if (num4 == 3)
			{
				for (int i = num5; i + 3 < num16; i += 4)
				{
					float num17 = BitConverter.ToSingle(array, i);
					array2[num15++] = Mathf.Clamp(num17, -1f, 1f);
				}
			}
			else
			{
				switch (num3)
				{
				case 32:
				{
					for (int m = num5; m + 3 < num16; m += 4)
					{
						int num20 = BitConverter.ToInt32(array, m);
						array2[num15++] = Mathf.Clamp((float)num20 / 2.1474836E+09f, -1f, 1f);
					}
					break;
				}
				case 24:
				{
					for (int k = num5; k + 2 < num16; k += 3)
					{
						int num18 = array[k] | (array[k + 1] << 8) | (array[k + 2] << 16);
						if (((uint)num18 & 0x800000u) != 0)
						{
							num18 |= -16777216;
						}
						array2[num15++] = Mathf.Clamp((float)num18 / 8388608f, -1f, 1f);
					}
					break;
				}
				case 16:
				{
					for (int l = num5; l + 1 < num16; l += 2)
					{
						short num19 = BitConverter.ToInt16(array, l);
						array2[num15++] = (float)num19 / 32768f;
					}
					break;
				}
				default:
				{
					for (int j = num5; j < num16; j++)
					{
						array2[num15++] = (float)(array[j] - 128) / 128f;
					}
					break;
				}
				}
			}
			int num21 = num15 / num;
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
			Type type = AccessTools.TypeByName("UnityEngine.AudioClip");
			if (type == null)
			{
				throw new Exception("AudioClip type not found");
			}
			MethodInfo methodInfo = AccessTools.Method(type, "Create", new Type[5]
			{
				typeof(string),
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(bool)
			}, (Type[])null);
			if (methodInfo == null)
			{
				throw new Exception("AudioClip.Create not found");
			}
			object obj = methodInfo.Invoke(null, new object[5] { fileNameWithoutExtension, num21, num, num2, false });
			if (obj == null)
			{
				throw new Exception("AudioClip.Create returned null");
			}
			MethodInfo methodInfo2 = AccessTools.Method(type, "SetData", new Type[2]
			{
				typeof(float[]),
				typeof(int)
			}, (Type[])null);
			if (methodInfo2 == null)
			{
				throw new Exception("AudioClip.SetData not found");
			}
			methodInfo2.Invoke(obj, new object[2] { array2, 0 });
			return (Object)((obj is Object) ? obj : null);
		}

		private static string ReadAscii(byte[] bytes, int offset, int len)
		{
			char[] array = new char[len];
			for (int i = 0; i < len; i++)
			{
				array[i] = (char)bytes[offset + i];
			}
			return new string(array);
		}

		private static bool GuidEquals(byte[] bytes, int offset, byte[] guidBytes)
		{
			if (bytes == null || guidBytes == null)
			{
				return false;
			}
			if (offset < 0 || offset + guidBytes.Length > bytes.Length)
			{
				return false;
			}
			for (int i = 0; i < guidBytes.Length; i++)
			{
				if (bytes[offset + i] != guidBytes[i])
				{
					return false;
				}
			}
			return true;
		}

		private void Update()
		{
			UpdateFfb();
		}

		private void OnDestroy()
		{
			ShutdownLogitech();
		}

		private static void SInputManager_GetInput_Postfix(sInputManager __instance)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			if (ShouldApply() && !((Object)(object)__instance == (Object)null) && !__instance.lockInput && !PauseSystem.paused && !_isInWalkingMode && TryGetCachedWheelState(out var state))
			{
				int axisValue = GetAxisValue(state, GetSteeringAxis());
				int axisValue2 = GetAxisValue(state, GetThrottleAxis());
				int axisValue3 = GetAxisValue(state, GetBrakeAxis());
				float num = NormalizeSteering(axisValue);
				float num2 = NormalizePedal(axisValue2, PedalKind.Throttle);
				float num3 = NormalizePedal(axisValue3, PedalKind.Brake);
				if (num2 < 0.05f)
				{
					num2 = 0f;
				}
				if (num3 < 0.05f)
				{
					num3 = 0f;
				}
				float num4 = Mathf.Clamp(num2 - num3, -1f, 1f);
				__instance.driveInput = new Vector2(num, num4);
				SetWheelLastInput(num, num4);
			}
		}

		private static bool SHUD_DoFuelMath_Prefix(sHUD __instance)
		{
			if (!ShouldApply() || (Object)(object)__instance == (Object)null)
			{
				return true;
			}
			if (!GetIgnitionEnabledEffective())
			{
				return false;
			}
			return true;
		}

		private static void SHUD_DoTemperature_Postfix(sHUD __instance)
		{
			if (ShouldApply() && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.navigation == (Object)null) && !((Object)(object)__instance.navigation.car == (Object)null) && !__instance.navigation.car.GuyActive && GetIgnitionFeatureEnabled() && !GetIgnitionEnabledEffective())
			{
				if (_ignitionOffSince < 0f)
				{
					_ignitionOffSince = Time.unscaledTime;
				}
				if (!(Time.unscaledTime - _ignitionOffSince < 30f))
				{
					__instance.AddWarning("truck temperature low");
					float num = __instance.temperatureRate * 0.5f;
					__instance.temperature = Mathf.Clamp(__instance.temperature - Time.deltaTime * num, 0f, __instance.temperatureLimit);
				}
			}
		}

		private static void EnsureHeadlightsRefs(object instance)
		{
			if (instance != null)
			{
				Type type = instance.GetType();
				if (!(_headlightsRuntimeType == type))
				{
					_headlightsRuntimeType = type;
					_headlightsHeadLightsField = AccessTools.Field(type, "headLights");
					_headlightsCarMatField = AccessTools.Field(type, "carMat");
					_headlightsEmissiveRegularField = AccessTools.Field(type, "emissiveRegular");
					_headlightsEmissiveBreakingField = AccessTools.Field(type, "emissiveBreaking");
					_headlightsHeadlightsOnField = AccessTools.Field(type, "headlightsOn");
					_headlightsModelField = AccessTools.Field(type, "model");
				}
			}
		}

		private static void EnsureLensFlareRefs()
		{
			if (_lensFlareSrpType == null)
			{
				_lensFlareSrpType = AccessTools.TypeByName("UnityEngine.Rendering.LensFlareComponentSRP");
			}
		}

		private static void EnsureFlareIntensityRefs()
		{
			if (_flareIntensityType == null)
			{
				_flareIntensityType = AccessTools.TypeByName("flareIntensity");
			}
		}

		private static bool LooksLikeHeadlightArtifactRenderer(Renderer r)
		{
			if ((Object)(object)r == (Object)null)
			{
				return false;
			}
			string text = (((Object)(object)((Component)r).gameObject != (Object)null) ? ((Object)((Component)r).gameObject).name : string.Empty);
			if (!string.IsNullOrEmpty(text))
			{
				if (text.IndexOf("tail", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("brake", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("indicator", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("signal", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("turn", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return false;
				}
				if (text.IndexOf("flare", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("glow", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("beam", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("headlight", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("head", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			try
			{
				Material sharedMaterial = r.sharedMaterial;
				if ((Object)(object)sharedMaterial != (Object)null)
				{
					string name = ((Object)sharedMaterial).name;
					if (!string.IsNullOrEmpty(name))
					{
						if (name.IndexOf("tail", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("brake", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("indicator", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("signal", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("turn", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							return false;
						}
						if (name.IndexOf("flare", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("glow", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("beam", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("headlight", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("head", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							return true;
						}
					}
					if ((Object)(object)sharedMaterial.shader != (Object)null)
					{
						string name2 = ((Object)sharedMaterial.shader).name;
						if (!string.IsNullOrEmpty(name2) && (name2.IndexOf("flare", StringComparison.OrdinalIgnoreCase) >= 0 || name2.IndexOf("glow", StringComparison.OrdinalIgnoreCase) >= 0 || name2.IndexOf("headlight", StringComparison.OrdinalIgnoreCase) >= 0))
						{
							return true;
						}
						if (!string.