Decompiled source of SebLogiWheel v1.0.3
BepInEx\plugins\SebLogiWheel\SebLogiWheel.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
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.