static void GetVehicleAutoBoxSetup(const FVehicleTransmissionData& Setup, PxVehicleAutoBoxData& PxSetup)
{
	for (int32 i = 0; i < Setup.ForwardGears.Num(); i++)
	{
		const FVehicleGearData& GearData = Setup.ForwardGears[i];
		PxSetup.mUpRatios[i] = GearData.UpRatio;
		PxSetup.mDownRatios[i] = GearData.DownRatio;
	}
	PxSetup.mUpRatios[PxVehicleGearsData::eNEUTRAL] = Setup.NeutralGearUpRatio;
	PxSetup.setLatency(Setup.GearAutoBoxLatency);
}
static void GetVehicleAutoBoxSetup(const FVehicleAutoBoxData& Setup, PxVehicleAutoBoxData& PxSetup)
{
	for (uint32 i = PxVehicleGearsData::eFIRST; i < PxVehicleGearsData::eGEARSRATIO_COUNT; i++)
	{
		const FGearUpDownRatio& RatioData = Setup.ForwardGearAutoBox[i - PxVehicleGearsData::eFIRST];
		PxSetup.mUpRatios[i] = RatioData.UpRatio;
		PxSetup.mDownRatios[i] = RatioData.DownRatio;
	}
	PxSetup.mUpRatios[PxVehicleGearsData::eNEUTRAL] = Setup.NeutralGearUpRatio;
	PxSetup.setLatency(Setup.GearAutoBoxLatency);
}
UWheeledVehicleMovementComponent4W::UWheeledVehicleMovementComponent4W(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP)
{
#if WITH_PHYSX
	// grab default values from physx
	PxVehicleDifferential4WData DefDifferentialSetup;
	TEnumAsByte<EVehicleDifferential4W::Type> DiffType((uint8)DefDifferentialSetup.mType);
	DifferentialSetup.DifferentialType = DiffType;
	DifferentialSetup.FrontRearSplit = DefDifferentialSetup.mFrontRearSplit;
	DifferentialSetup.FrontLeftRightSplit = DefDifferentialSetup.mFrontLeftRightSplit;
	DifferentialSetup.RearLeftRightSplit = DefDifferentialSetup.mRearLeftRightSplit;
	DifferentialSetup.CentreBias = DefDifferentialSetup.mCentreBias;
	DifferentialSetup.FrontBias = DefDifferentialSetup.mFrontBias;
	DifferentialSetup.RearBias = DefDifferentialSetup.mRearBias;

	const PxReal LengthScale = 100.f; // Convert default from m to cm

	PxVehicleEngineData DefEngineData;
	EngineSetup.MOI = DefEngineData.mMOI * LengthScale * LengthScale;
	EngineSetup.PeakTorque = 1000 * LengthScale * LengthScale;
	EngineSetup.MaxOmega = 1000;
	EngineSetup.DampingRateFullThrottle = 0.5f * LengthScale * LengthScale;
	EngineSetup.DampingRateZeroThrottleClutchEngaged = 2.0f * LengthScale * LengthScale;
	EngineSetup.DampingRateZeroThrottleClutchDisengaged = 0.5f * LengthScale * LengthScale;

	PxVehicleClutchData DefClutchData;
	ClutchStrength = DefClutchData.mStrength * LengthScale * LengthScale; // convert from m to cm scale

	PxVehicleAckermannGeometryData DefAckermannSetup;
	AckermannAccuracy = DefAckermannSetup.mAccuracy;

	PxVehicleGearsData DefGearSetup;
	GearSetup.GearSwitchTime = DefGearSetup.mSwitchTime;
	GearSetup.ReverseGearRatio = DefGearSetup.mRatios[PxVehicleGearsData::eREVERSE];
	for (uint32 i = PxVehicleGearsData::eFIRST; i < DefGearSetup.mNbRatios; i++)
	{
		GearSetup.ForwardGearRatios.Add(DefGearSetup.mRatios[i]);
	}
	GearSetup.RatioMultiplier =  DefGearSetup.mFinalRatio; 

	PxVehicleAutoBoxData DefAutoBoxSetup;
	for (uint32 i = PxVehicleGearsData::eFIRST; i < PxVehicleGearsData::eGEARSRATIO_COUNT; i++)
	{
		FGearUpDownRatio RatioData;
		RatioData.UpRatio = DefAutoBoxSetup.mUpRatios[i];
		RatioData.DownRatio = DefAutoBoxSetup.mUpRatios[i];
		AutoBoxSetup.ForwardGearAutoBox.Add(RatioData);
	}
	AutoBoxSetup.NeutralGearUpRatio = DefAutoBoxSetup.mUpRatios[PxVehicleGearsData::eNEUTRAL];
	AutoBoxSetup.GearAutoBoxLatency = DefAutoBoxSetup.getLatency();
	bUseGearAutoBox = true;

	MaxSteeringSpeed = 6000.0f; // editable in vehicle blueprint
	SteeringCurve.AddZeroed(4);
	SteeringCurve[0].InVal = 0.0f;
	SteeringCurve[0].OutVal = 0.75f;
	SteeringCurve[1].InVal = 0.05f;
	SteeringCurve[1].OutVal = 0.75f;
	SteeringCurve[2].InVal = 0.25f;
	SteeringCurve[2].OutVal = 0.125f;
	SteeringCurve[3].InVal = 1.0f;
	SteeringCurve[3].OutVal = 0.1f;

	WheelSetups.AddZeroed(4);
	for (int i = 0 ; i < WheelSetups.Num(); ++i)
	{
		WheelSetups[i].WheelClass = UVehicleWheel::StaticClass();
	}
#endif // WITH_PHYSX
}
UWheeledVehicleMovementComponent4W::UWheeledVehicleMovementComponent4W(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
#if WITH_VEHICLE
	// grab default values from physx
	PxVehicleDifferential4WData DefDifferentialSetup;
	TEnumAsByte<EVehicleDifferential4W::Type> DiffType((uint8)DefDifferentialSetup.mType);
	DifferentialSetup.DifferentialType = DiffType;
	DifferentialSetup.FrontRearSplit = DefDifferentialSetup.mFrontRearSplit;
	DifferentialSetup.FrontLeftRightSplit = DefDifferentialSetup.mFrontLeftRightSplit;
	DifferentialSetup.RearLeftRightSplit = DefDifferentialSetup.mRearLeftRightSplit;
	DifferentialSetup.CentreBias = DefDifferentialSetup.mCentreBias;
	DifferentialSetup.FrontBias = DefDifferentialSetup.mFrontBias;
	DifferentialSetup.RearBias = DefDifferentialSetup.mRearBias;

	PxVehicleEngineData DefEngineData;
	EngineSetup.MOI = DefEngineData.mMOI;
	EngineSetup.MaxRPM = OmegaToRPM(DefEngineData.mMaxOmega);
	EngineSetup.DampingRateFullThrottle = DefEngineData.mDampingRateFullThrottle;
	EngineSetup.DampingRateZeroThrottleClutchEngaged = DefEngineData.mDampingRateZeroThrottleClutchEngaged;
	EngineSetup.DampingRateZeroThrottleClutchDisengaged = DefEngineData.mDampingRateZeroThrottleClutchDisengaged;

	// Convert from PhysX curve to ours
	FRichCurve* TorqueCurveData = EngineSetup.TorqueCurve.GetRichCurve();
	for(PxU32 KeyIdx=0; KeyIdx<DefEngineData.mTorqueCurve.getNbDataPairs(); KeyIdx++)
	{
		float Input = DefEngineData.mTorqueCurve.getX(KeyIdx) * EngineSetup.MaxRPM;
		float Output = DefEngineData.mTorqueCurve.getY(KeyIdx) * DefEngineData.mPeakTorque;
		TorqueCurveData->AddKey(Input, Output);
	}

	PxVehicleClutchData DefClutchData;
	TransmissionSetup.ClutchStrength = DefClutchData.mStrength;

	PxVehicleAckermannGeometryData DefAckermannSetup;
	AckermannAccuracy = DefAckermannSetup.mAccuracy;

	PxVehicleGearsData DefGearSetup;
	TransmissionSetup.GearSwitchTime = DefGearSetup.mSwitchTime;
	TransmissionSetup.ReverseGearRatio = DefGearSetup.mRatios[PxVehicleGearsData::eREVERSE];
	TransmissionSetup.FinalRatio = DefGearSetup.mFinalRatio;

	PxVehicleAutoBoxData DefAutoBoxSetup;
	TransmissionSetup.NeutralGearUpRatio = DefAutoBoxSetup.mUpRatios[PxVehicleGearsData::eNEUTRAL];
	TransmissionSetup.GearAutoBoxLatency = DefAutoBoxSetup.getLatency();
	TransmissionSetup.bUseGearAutoBox = true;

	for (uint32 i = PxVehicleGearsData::eFIRST; i < DefGearSetup.mNbRatios; i++)
	{
		FVehicleGearData GearData;
		GearData.DownRatio = DefAutoBoxSetup.mDownRatios[i];
		GearData.UpRatio = DefAutoBoxSetup.mUpRatios[i];
		GearData.Ratio = DefGearSetup.mRatios[i];
		TransmissionSetup.ForwardGears.Add(GearData);
	}
	
	// Init steering speed curve
	FRichCurve* SteeringCurveData = SteeringCurve.GetRichCurve();
	SteeringCurveData->AddKey(0.f, 1.f);
	SteeringCurveData->AddKey(20.f, 0.9f);
	SteeringCurveData->AddKey(60.f, 0.8f);
	SteeringCurveData->AddKey(120.f, 0.7f);

	// Initialize WheelSetups array with 4 wheels
	WheelSetups.SetNum(4);
#endif // WITH_VEHICLE
}