using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
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.1.3")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.1.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
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 = new DIJOYSTATE2ENGINES
{
rglSlider = new int[2],
rgdwPOV = new uint[4],
rgbButtons = new byte[128],
rglVSlider = new int[2],
rglASlider = new int[2],
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.1.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 _))
{
__instance.input.x = steer;
}
}
}
internal enum PedalKind
{
Throttle,
Brake,
Clutch
}
internal enum AxisId
{
lX,
lY,
lZ,
lRx,
lRy,
lRz,
slider0,
slider1
}
internal enum ButtonBindAction
{
InteractOk = 0,
Back = 1,
MapItems = 2,
Pause = 3,
Camera = 5,
ResetVehicle = 6,
Horn = 8,
RadioPower = 9,
RadioScanToggle = 10,
RadioScanLeft = 11,
RadioScanRight = 12
}
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";
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 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.1.3";
private static Plugin _instance;
internal static void ClearAllUserPrefs()
{
string[] array = new string[21]
{
"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_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[16]
{
"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_Bind_Modifier"
};
string[] array2 = new string[5] { "ELWS_FfbOverall", "ELWS_FfbSpring", "ELWS_FfbDamper", "ELWS_SteerGain", "ELWS_SteerDeadzone" };
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 num = PlayerPrefs.GetInt(GetBindPrefKey(layer, action), -1);
if (num < 0)
{
num = PlayerPrefs.GetInt(GetLegacyBindPrefKey(layer, action), -1);
}
if (num < 0)
{
return new BindingInput
{
Kind = BindingKind.None,
Code = 0
};
}
if (num >= 1000)
{
return new BindingInput
{
Kind = BindingKind.Pov,
Code = Mathf.Clamp(num - 1000, 0, 3)
};
}
return new BindingInput
{
Kind = BindingKind.Button,
Code = Mathf.Clamp(num, 0, 127)
};
}
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 num = PlayerPrefs.GetInt("ELWS_Bind_Modifier", -1);
if (num < 0)
{
return new BindingInput
{
Kind = BindingKind.None,
Code = 0
};
}
if (num >= 1000)
{
return new BindingInput
{
Kind = BindingKind.Pov,
Code = Mathf.Clamp(num - 1000, 0, 3)
};
}
return new BindingInput
{
Kind = BindingKind.Button,
Code = Mathf.Clamp(num, 0, 127)
};
}
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.Horn => "Horn",
ButtonBindAction.RadioPower => "Radio Pwr",
ButtonBindAction.RadioScanToggle => "Scan",
ButtonBindAction.RadioScanLeft => "Prev Ch",
ButtonBindAction.RadioScanRight => "Next Ch",
_ => 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;
}
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 item = new LogiDeviceSnapshot
{
Index = i,
Connected = true,
Name = TryGetWheelFriendlyName(i),
Path = TryGetWheelDevicePath(i)
};
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 logiDeviceSnapshot = list[j];
int num3 = 0;
if (logiDeviceSnapshot.IsWheel)
{
num3 += 100;
}
if (logiDeviceSnapshot.IsLogitech)
{
num3 += 20;
}
if (logiDeviceSnapshot.IsG920)
{
num3 += 50;
}
if (logiDeviceSnapshot.IsG29)
{
num3 += 40;
}
if (logiDeviceSnapshot.IsGamepad)
{
num3 -= 100;
}
if (logiDeviceSnapshot.IsJoystick && !logiDeviceSnapshot.IsWheel)
{
num3 -= 20;
}
if (logiDeviceSnapshot.Vid == 1133)
{
num3 += 10;
}
if (num3 > num2)
{
num2 = num3;
num = logiDeviceSnapshot.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", GetAxisValue(state, GetSteeringAxis()));
}
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 num = PlayerPrefs.GetInt("ELWS_Cal_SteerLeft", -32768);
int num2 = PlayerPrefs.GetInt("ELWS_Cal_SteerRight", 32767);
int num3 = PlayerPrefs.GetInt("ELWS_Cal_SteerCenter", (num + num2) / 2);
if (num2 == num)
{
return 0f;
}
float num5;
if (rawX >= num3)
{
float num4 = num2 - num3;
num5 = ((num4 <= 0.001f) ? 0f : ((float)(rawX - num3) / num4));
}
else
{
float num6 = num3 - num;
num5 = ((num6 <= 0.001f) ? 0f : ((float)(-(num3 - rawX)) / num6));
}
num5 = Mathf.Clamp(num5, -1f, 1f);
float steeringDeadzone = GetSteeringDeadzone();
float num7 = Mathf.Abs(num5);
num5 = ((!(num7 <= steeringDeadzone)) ? (Mathf.Sign(num5) * Mathf.Clamp01((num7 - steeringDeadzone) / Mathf.Max(0.0001f, 1f - steeringDeadzone))) : 0f);
float steeringGain = GetSteeringGain();
return Mathf.Clamp(num5 * 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 num = PlayerPrefs.GetInt(text, 32767);
int num2 = PlayerPrefs.GetInt(text2, -32768);
float num3 = Mathf.InverseLerp((float)num, (float)num2, (float)rawAxis);
num3 = Mathf.Clamp01(num3);
if (num3 < 0.05f)
{
num3 = 0f;
}
return num3;
}
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 != FfbTestEffect.None)
{
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.LogiSetPreferredControllerProperties(new LogitechGSDK.LogiControllerPropertiesData
{
forceEnable = forceEnable,
overallGain = Mathf.RoundToInt(GetFfbOverallGain() * 100f),
springGain = Mathf.RoundToInt(GetFfbSpringGain() * 100f),
damperGain = Mathf.RoundToInt(GetFfbDamperGain() * 100f),
defaultSpringEnabled = false,
defaultSpringGain = 0,
combinePedals = false,
wheelRange = GetWheelRange(),
gameSettingsEnabled = true,
allowGameSettings = true
});
}
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_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Expected O, but got Unknown
//IL_00cf: Expected O, but got Unknown
_log = ((BaseUnityPlugin)this).Logger;
_instance = this;
ConfigUtil.CopyLegacyConfigIfNeeded("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");
val.PatchAll(typeof(Plugin).Assembly);
PatchByName(val, "sCarController", "Update", "SCarController_Update_Prefix");
PatchByName(val, "sInputManager", "GetInput", null, "SInputManager_GetInput_Postfix");
DetectWheelOnce();
TryInitLogitech();
_log.LogInfo((object)"SebLogiWheel loaded.");
}
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 void SCarController_Update_Prefix(object __instance)
{
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
if (!ShouldApply() || __instance == null)
{
return;
}
sCarController val = (sCarController)((__instance is sCarController) ? __instance : null);
if ((Object)(object)val == (Object)null)
{
return;
}
_isInWalkingMode = val.GuyActive;
if ((Object)(object)val.rb != (Object)null)
{
Vector3 linearVelocity = val.rb.linearVelocity;
_currentSpeedKmh = ((Vector3)(ref linearVelocity)).magnitude * 3.6f;
}
if (val.wheels == null)
{
return;
}
float num = 0f;
bool isOffRoad = false;
Wheel[] wheels = val.wheels;
foreach (Wheel val2 in wheels)
{
if (val2 != null)
{
num += val2.slide;
if ((Object)(object)val2.suspention != (Object)null && string.Equals(val2.suspention.contactTag, "offRoad", StringComparison.OrdinalIgnoreCase))
{
isOffRoad = true;
}
}
}
_isOffRoad = isOffRoad;
_isSliding = num > 2f;
}
private static void PatchByName(Harmony harmony, string typeName, string methodName, string prefix = null, string postfix = null)
{
HarmonyUtil.PatchByName(harmony, typeof(Plugin), typeName, methodName, prefix, postfix, (Action<string>)LogDebug);
}
}
public class WheelMenuWindow : CartridgeWindowBase
{
private enum CalStep
{
None,
SteeringCenter,
SteeringLeft,
SteeringRight,
ThrottleReleased,
ThrottlePressed,
BrakeReleased,
BrakePressed,
ClutchReleased,
ClutchPressed
}
private enum Page
{
Main = 0,
Ffb = 1,
Steering = 2,
Calibration = 4,
CalibrationWizard = 5,
Bindings = 6
}
public const string FileName = "wheel";
public const string ListenerName = "G920Menu";
public const string ListenerData = "listener_G920Menu";
private Page _page;
private CalStep _calStep;
public override void FrameUpdate(WindowView view)
{
if (Plugin.ConsumeOpenCalibrationWizardRequest())
{
_page = Page.CalibrationWizard;
}
if (Plugin.ConsumeOpenAxisMappingRequest())
{
_page = Page.Bindings;
}
((CartridgeWindowBase)this).FrameUpdate(view);
}
public override void BackButtonPressed()
{
if (_page == Page.CalibrationWizard)
{
_calStep = CalStep.None;
_page = Page.Calibration;
}
else if (_page != Page.Main)
{
_calStep = CalStep.None;
_page = Page.Main;
}
else
{
((CartridgeWindowBase)this).ReturnToSebCoreAndClose();
}
}
protected override void DrawWindow(Rect p)
{
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
float center = ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f - 16f;
float y = ((Rect)(ref p)).y + 10f;
float num = 12f;
float num2 = 4f;
Plugin.SetWheelMenuActive(active: true);
Plugin.SetFfbPageActive(_page == Page.Ffb);
Plugin.SetCalibrationWizardActive(_page == Page.CalibrationWizard);
if (_page == Page.Main)
{
base.Util.Label("Wheel Settings", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += num + num2;
}
if (_page == Page.Main)
{
DrawMain(p, center, ref y, num, num2);
}
else if (_page == Page.Ffb)
{
DrawFfb(p, center, ref y, num, num2);
}
else if (_page == Page.Steering)
{
DrawSteering(p, center, ref y, num, num2);
}
else if (_page == Page.Calibration)
{
DrawCalibration(p, center, ref y, num, num2);
}
else if (_page == Page.CalibrationWizard)
{
DrawCalibrationWizard(p, center, ref y, num, num2);
}
else
{
DrawBindings(p, center, ref y, num, num2);
}
}
private void DrawMain(Rect p, float center, ref float y, float line, float sectionGap)
{
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
float num = ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f;
float num2 = 22f;
if (base.Util.FancyButton("Button Binds", num, y, 0f))
{
CartridgeApps.TryOpen(base.Util.M, base.Util.R, CartridgeApps.Binds);
}
y += num2;
if (base.Util.FancyButton("Axis Mapping", num, y, 0f))
{
_page = Page.Bindings;
}
y += num2;
if (base.Util.FancyButton("Force Feedback", num, y, 0f))
{
_page = Page.Ffb;
}
y += num2;
if (base.Util.FancyButton("Steering", num, y, 0f))
{
_page = Page.Steering;
}
y += num2;
if (base.Util.FancyButton("Calibration", num, y, 0f))
{
_page = Page.Calibration;
}
float num3 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 66f;
float num4 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 54f;
float num5 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 18f;
base.Util.Label("Logitech SDK: " + Plugin.GetLogitechStatus(), num, num3);
if (base.Util.SimpleButton("Retry SDK", num, num4))
{
Plugin.ForceReinitLogitech(forceReconnect: true);
}
if (base.Util.SimpleButton("Back", num, num5))
{
((CartridgeWindowBase)this).BackButtonPressed();
}
}
private void DrawFfb(Rect p, float center, ref float y, float line, float sectionGap)
{
base.Util.Label("Force Feedback", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line;
float num = ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f;
float num2 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 30f;
float num3 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 18f;
if (base.Util.SimpleButton("Reset Defaults", num, num2))
{
Plugin.ResetFfbDefaults();
}
if (base.Util.SimpleButton("Back", num, num3))
{
_page = Page.Main;
return;
}
y += sectionGap;
bool ffbEnabled = Plugin.GetFfbEnabled();
bool? flag = base.Util.Toggle("Enable FFB", ffbEnabled, center, y);
if (flag.HasValue)
{
Plugin.SetFfbEnabled(flag.Value);
}
y += line;
float ffbOverallGain = Plugin.GetFfbOverallGain();
base.Util.ValueLabel($"{Mathf.RoundToInt(ffbOverallGain * 100f)}%", ((Rect)(ref p)).x + ((Rect)(ref p)).width - 12f, y);
float? num4 = base.Util.Slider("Strength", ffbOverallGain, center, y, ref base.MouseYLock);
if (num4.HasValue)
{
Plugin.SetFfbOverallGain(num4.Value);
}
y += line;
float ffbSpringGain = Plugin.GetFfbSpringGain();
base.Util.ValueLabel($"{Mathf.RoundToInt(ffbSpringGain * 100f)}%", ((Rect)(ref p)).x + ((Rect)(ref p)).width - 12f, y);
float? num5 = base.Util.Slider("Spring", ffbSpringGain, center, y, ref base.MouseYLock);
if (num5.HasValue)
{
Plugin.SetFfbSpringGain(num5.Value);
}
y += line;
float ffbDamperGain = Plugin.GetFfbDamperGain();
base.Util.ValueLabel($"{Mathf.RoundToInt(ffbDamperGain * 100f)}%", ((Rect)(ref p)).x + ((Rect)(ref p)).width - 12f, y);
float? num6 = base.Util.Slider("Damper", ffbDamperGain, center, y, ref base.MouseYLock);
if (num6.HasValue)
{
Plugin.SetFfbDamperGain(num6.Value);
}
}
private void DrawSteering(Rect p, float center, ref float y, float line, float sectionGap)
{
base.Util.Label("Steering", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line;
float num = ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f;
float num2 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 30f;
float num3 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 18f;
if (base.Util.SimpleButton("Reset Defaults", num, num2))
{
Plugin.ResetSteeringDefaults();
}
if (base.Util.SimpleButton("Back", num, num3))
{
_page = Page.Main;
return;
}
y += sectionGap;
int wheelRange = Plugin.GetWheelRange();
base.Util.ValueLabel($"{wheelRange} deg", ((Rect)(ref p)).x + ((Rect)(ref p)).width - 12f, y);
float num4 = Mathf.InverseLerp(180f, 900f, (float)wheelRange);
float? num5 = base.Util.Slider("Range", num4, center, y, ref base.MouseYLock);
if (num5.HasValue)
{
Plugin.SetWheelRange(Mathf.Clamp(Mathf.RoundToInt(Mathf.Lerp(180f, 900f, num5.Value)), 180, 900));
}
y += line;
float steeringGain = Plugin.GetSteeringGain();
base.Util.ValueLabel($"{steeringGain:0.00}x", ((Rect)(ref p)).x + ((Rect)(ref p)).width - 12f, y);
float num6 = Mathf.InverseLerp(0.5f, 3f, steeringGain);
float? num7 = base.Util.Slider("Steer Sens", num6, center, y, ref base.MouseYLock);
if (num7.HasValue)
{
Plugin.SetSteeringGain(Mathf.Lerp(0.5f, 3f, num7.Value));
}
y += line;
float steeringDeadzone = Plugin.GetSteeringDeadzone();
base.Util.ValueLabel($"{Mathf.RoundToInt(steeringDeadzone * 100f)}%", ((Rect)(ref p)).x + ((Rect)(ref p)).width - 12f, y);
float num8 = Mathf.InverseLerp(0f, 0.12f, steeringDeadzone);
float? num9 = base.Util.Slider("Deadzone", num8, center, y, ref base.MouseYLock);
if (num9.HasValue)
{
Plugin.SetSteeringDeadzone(Mathf.Lerp(0f, 0.12f, num9.Value));
}
}
private void DrawBindings(Rect p, float center, ref float y, float line, float sectionGap)
{
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
base.Util.Label("Axis Mapping", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line;
float num = ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f;
float num2 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 18f;
if (base.Util.SimpleButton("Back", num, num2))
{
_page = Page.Main;
return;
}
y += sectionGap;
DrawBindingsAxes(p, center, ref y, line, sectionGap);
}
private void DrawBindingsAxes(Rect p, float center, ref float y, float line, float sectionGap)
{
if (!Plugin.TryGetCachedWheelState(out var state))
{
string logitechStatus = Plugin.GetLogitechStatus();
if (logitechStatus == "No wheel")
{
base.Util.Label("No wheel detected.", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
}
else
{
base.Util.Label("Logitech SDK: " + logitechStatus, ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
}
return;
}
Plugin.AxisId steeringAxis = Plugin.GetSteeringAxis();
Plugin.AxisId throttleAxis = Plugin.GetThrottleAxis();
Plugin.AxisId brakeAxis = Plugin.GetBrakeAxis();
Plugin.AxisId clutchAxis = Plugin.GetClutchAxis();
if (base.Util.CycleButtonRaw("Steering", steeringAxis.ToString(), center, y))
{
Plugin.SetSteeringAxis(NextAxis(steeringAxis));
_calStep = CalStep.None;
}
float num = Plugin.NormalizeSteering(Plugin.GetAxisValue(state, steeringAxis));
base.Util.ValueLabel($"{num:+0.00;-0.00;0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width - 12f, y);
y += line;
if (base.Util.CycleButtonRaw("Throttle", throttleAxis.ToString(), center, y))
{
Plugin.SetThrottleAxis(NextAxis(throttleAxis));
_calStep = CalStep.None;
}
float num2 = Plugin.NormalizePedal(Plugin.GetAxisValue(state, throttleAxis), Plugin.PedalKind.Throttle);
base.Util.ValueLabel($"{num2:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width - 12f, y);
y += line;
if (base.Util.CycleButtonRaw("Brake", brakeAxis.ToString(), center, y))
{
Plugin.SetBrakeAxis(NextAxis(brakeAxis));
_calStep = CalStep.None;
}
float num3 = Plugin.NormalizePedal(Plugin.GetAxisValue(state, brakeAxis), Plugin.PedalKind.Brake);
base.Util.ValueLabel($"{num3:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width - 12f, y);
y += line;
if (base.Util.CycleButtonRaw("Clutch", clutchAxis.ToString(), center, y))
{
Plugin.SetClutchAxis(NextAxis(clutchAxis));
_calStep = CalStep.None;
}
float num4 = Plugin.NormalizePedal(Plugin.GetAxisValue(state, clutchAxis), Plugin.PedalKind.Clutch);
base.Util.ValueLabel($"{num4:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width - 12f, y);
y += line + sectionGap;
base.Util.Label("Live Axes", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line;
string text = $"lX={state.lX} lY={state.lY} lZ={state.lZ}";
string text2 = $"lRx={state.lRx} lRy={state.lRy} lRz={state.lRz}";
int num5 = ((state.rglSlider != null && state.rglSlider.Length != 0) ? state.rglSlider[0] : 0);
int num6 = ((state.rglSlider != null && state.rglSlider.Length > 1) ? state.rglSlider[1] : 0);
string text3 = $"slider0={num5} slider1={num6}";
base.Util.Label(text, ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label(text2, ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label(text3, ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label(GetHeldButtonsLabel(state), ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line;
base.Util.Label($"steer={num:+0.00;-0.00;0.00} thr={num2:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label($"brk={num3:0.00} clu={num4:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
}
private void DrawCalibration(Rect p, float center, ref float y, float line, float sectionGap)
{
base.Util.Label("Calibration", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line;
float num = ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f;
float num2 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 18f;
float num3 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 30f;
float num4 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 72f;
if (base.Util.FancyButton("Calibrate", num, num4, 0f))
{
_calStep = CalStep.SteeringCenter;
_page = Page.CalibrationWizard;
}
if (base.Util.SimpleButton("Clear Calibration", num, num3))
{
Plugin.ClearCalibration();
_calStep = CalStep.None;
}
if (base.Util.SimpleButton("Back", num, num2))
{
_calStep = CalStep.None;
_page = Page.Main;
return;
}
y += line + sectionGap;
if (!Plugin.TryGetLogiState(out var state))
{
string logitechStatus = Plugin.GetLogitechStatus();
if (logitechStatus == "No wheel")
{
base.Util.Label("No wheel detected.", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
}
else
{
base.Util.Label("Logitech SDK: " + logitechStatus, ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
}
return;
}
base.Util.Label("Live Axes", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line;
string text = $"lX={state.lX} lY={state.lY} lZ={state.lZ}";
string text2 = $"lRx={state.lRx} lRy={state.lRy} lRz={state.lRz}";
int num5 = ((state.rglSlider != null && state.rglSlider.Length != 0) ? state.rglSlider[0] : 0);
int num6 = ((state.rglSlider != null && state.rglSlider.Length > 1) ? state.rglSlider[1] : 0);
string text3 = $"slider0={num5} slider1={num6}";
base.Util.Label(text, ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label(text2, ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label(text3, ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label(GetHeldButtonsLabel(state), ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line + sectionGap;
int axisValue = Plugin.GetAxisValue(state, Plugin.GetThrottleAxis());
int axisValue2 = Plugin.GetAxisValue(state, Plugin.GetBrakeAxis());
float num7 = Plugin.NormalizePedal(axisValue, Plugin.PedalKind.Throttle);
float num8 = Plugin.NormalizePedal(axisValue2, Plugin.PedalKind.Brake);
float num9 = Plugin.NormalizePedal(Plugin.GetAxisValue(state, Plugin.GetClutchAxis()), Plugin.PedalKind.Clutch);
base.Util.Label($"Current throttle: {num7:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label($"Current brake: {num8:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label($"Current clutch: {num9:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line;
}
private void DrawCalibrationWizard(Rect p, float center, ref float y, float line, float sectionGap)
{
base.Util.Label("Calibration Wizard", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line;
float num = ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f;
float num2 = ((Rect)(ref p)).y + ((Rect)(ref p)).height - 18f;
if (base.Util.SimpleButton("Cancel", num, num2))
{
_calStep = CalStep.None;
_page = Page.Calibration;
return;
}
y += sectionGap;
if (!Plugin.TryGetLogiState(out var state))
{
string logitechStatus = Plugin.GetLogitechStatus();
if (logitechStatus == "No wheel")
{
base.Util.Label("No wheel detected.", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
}
else
{
base.Util.Label("Logitech SDK: " + logitechStatus, ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
}
return;
}
string calPrompt = GetCalPrompt(_calStep);
base.Util.Label(calPrompt, ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line + sectionGap;
int axisValue = Plugin.GetAxisValue(state, Plugin.GetSteeringAxis());
int axisValue2 = Plugin.GetAxisValue(state, Plugin.GetThrottleAxis());
int axisValue3 = Plugin.GetAxisValue(state, Plugin.GetBrakeAxis());
int axisValue4 = Plugin.GetAxisValue(state, Plugin.GetClutchAxis());
base.Util.Label($"steer={axisValue}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label($"thr={axisValue2}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label($"brk={axisValue3}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label($"clu={axisValue4}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line + sectionGap;
float num3 = Plugin.NormalizeSteering(axisValue);
float num4 = Plugin.NormalizePedal(axisValue2, Plugin.PedalKind.Throttle);
float num5 = Plugin.NormalizePedal(axisValue3, Plugin.PedalKind.Brake);
float num6 = Plugin.NormalizePedal(axisValue4, Plugin.PedalKind.Clutch);
base.Util.Label($"steer norm={num3:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label($"thr norm={num4:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label($"brk norm={num5:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line - 2f;
base.Util.Label($"clu norm={num6:0.00}", ((Rect)(ref p)).x + ((Rect)(ref p)).width / 2f, y);
y += line + sectionGap;
float num7 = Mathf.Min(y, num2 - 34f);
if (base.Util.FancyButton("Capture", num, num7, 0f) && Plugin.TryGetLogiState(out var state2))
{
CaptureStep(_calStep, state2);
_calStep = NextStep(_calStep);
if (_calStep == CalStep.None)
{
_page = Page.Calibration;
}
}
}
private static Plugin.AxisId NextAxis(Plugin.AxisId axis)
{
int num = (int)(axis + 1);
if (num > 7)
{
num = 0;
}
return (Plugin.AxisId)num;
}
private static string GetHeldButtonsLabel(LogitechGSDK.DIJOYSTATE2ENGINES state)
{
if (state.rgbButtons == null || state.rgbButtons.Length == 0)
{
return "Buttons held: none";
}
StringBuilder stringBuilder = new StringBuilder("Buttons held: ");
int num = 0;
int num2 = 0;
for (int i = 0; i < state.rgbButtons.Length; i++)
{
if (state.rgbButtons[i] < 128)
{
continue;
}
num2++;
if (num < 8)
{
if (num > 0)
{
stringBuilder.Append(", ");
}
stringBuilder.Append(i);
num++;
}
}
if (num2 == 0)
{
return "Buttons held: none";
}
if (num2 > num)
{
stringBuilder.Append(" +");
stringBuilder.Append(num2 - num);
}
return stringBuilder.ToString();
}
private static string GetCalPrompt(CalStep step)
{
return step switch
{
CalStep.SteeringCenter => "Center the wheel",
CalStep.SteeringLeft => "Turn fully left",
CalStep.SteeringRight => "Turn fully right",
CalStep.ThrottleReleased => "Release throttle",
CalStep.ThrottlePressed => "Press throttle fully",
CalStep.BrakeReleased => "Release brake",
CalStep.BrakePressed => "Press brake fully",
CalStep.ClutchReleased => "Release clutch",
CalStep.ClutchPressed => "Press clutch fully",
_ => "",
};
}
private static CalStep NextStep(CalStep step)
{
return step switch
{
CalStep.SteeringCenter => CalStep.SteeringLeft,
CalStep.SteeringLeft => CalStep.SteeringRight,
CalStep.SteeringRight => CalStep.ThrottleReleased,
CalStep.ThrottleReleased => CalStep.ThrottlePressed,
CalStep.ThrottlePressed => CalStep.BrakeReleased,
CalStep.BrakeReleased => CalStep.BrakePressed,
CalStep.BrakePressed => CalStep.ClutchReleased,
CalStep.ClutchReleased => CalStep.ClutchPressed,
CalStep.ClutchPressed => CalStep.None,
_ => CalStep.None,
};
}
private static void CaptureStep(CalStep step, LogitechGSDK.DIJOYSTATE2ENGINES state)
{
switch (step)
{
case CalStep.SteeringCenter:
PlayerPrefs.SetInt("ELWS_Cal_SteerCenter", Plugin.GetAxisValue(state, Plugin.GetSteeringAxis()));
break;
case CalStep.SteeringLeft:
PlayerPrefs.SetInt("ELWS_Cal_SteerLeft", Plugin.GetAxisValue(state, Plugin.GetSteeringAxis()));
break;
case CalStep.SteeringRight:
PlayerPrefs.SetInt("ELWS_Cal_SteerRight", Plugin.GetAxisValue(state, Plugin.GetSteeringAxis()));
break;
case CalStep.ThrottleReleased:
PlayerPrefs.SetInt("ELWS_Cal_ThrottleReleased", Plugin.GetAxisValue(state, Plugin.GetThrottleAxis()));
break;
case CalStep.ThrottlePressed:
PlayerPrefs.SetInt("ELWS_Cal_ThrottlePressed", Plugin.GetAxisValue(state, Plugin.GetThrottleAxis()));
break;
case CalStep.BrakeReleased:
PlayerPrefs.SetInt("ELWS_Cal_BrakeReleased", Plugin.GetAxisValue(state, Plugin.GetBrakeAxis()));
break;
case CalStep.BrakePressed:
PlayerPrefs.SetInt("ELWS_Cal_BrakePressed", Plugin.GetAxisValue(state, Plugin.GetBrakeAxis()));
break;
case CalStep.ClutchReleased:
PlayerPrefs.SetInt("ELWS_Cal_ClutchReleased", Plugin.GetAxisValue(state, Plugin.GetClutchAxis()));
break;
case CalStep.ClutchPressed:
PlayerPrefs.SetInt("ELWS_Cal_ClutchPressed", Plugin.GetAxisValue(state, Plugin.GetClutchAxis()));
break;
}
}
}
}