void URealmCharacterMovementComponent::IgnoreMovement()
{
	//end any dashes this character may be performing
	EndDash();

	StopMovementImmediately();
	SetMovementMode(MOVE_None);
}
void URealmCharacterMovementComponent::EndDash()
{
	if (!bCharacterDashing)
		return;

	bCharacterDashing = false;
	StopMovementImmediately();
	SetMovementMode(MOVE_Walking);

	AGameCharacter* gc = Cast<AGameCharacter>(CharacterOwner);
	if (IsValid(gc))
	{
		gc->bAcceptingMoveCommands = true;
		gc->CharacterDashFinished();
	}
}
bool URealmCharacterMovementComponent::HandlePendingLaunch()
{
	if (!PendingLaunchVelocity.IsZero() && HasValidData())
	{
		Velocity = PendingLaunchVelocity;
		PendingLaunchVelocity = FVector::ZeroVector;
		if (bCharacterWantsDash)
		{
			StopMovementImmediately();
			SetMovementMode(MOVE_Flying);
			bCharacterWantsDash = false;
			bCharacterDashing = true;
		}
		else
			SetMovementMode(MOVE_Falling);

		return true;
	}

	return false;
}
// Called every frame
void UCustomMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// Stop if CapsuleComponet is invalid
	if (CapsuleComponent == NULL)
	{
		return;
	}

	// Update CurrentTraceShapeScale
	if (CurrentTraceShapeScale != TraceShapeScale)
	{
		CurrentTraceShapeScale = FMath::Clamp<float>(TraceShapeScale, 0.0f, 1.0f - KINDA_SMALL_NUMBER);
	}

	/* Local Variables */
	const EDrawDebugTrace::Type DrawDebugType = bDebugIsEnabled ? DebugDrawType : EDrawDebugTrace::None;
	const ECollisionChannel CollisionChannel = CapsuleComponent->GetCollisionObjectType();
	const FVector TraceStart = CapsuleComponent->GetComponentLocation();
	const float CapsuleHalfHeight = CapsuleComponent->GetScaledCapsuleHalfHeight();
	float ShapeRadius = CapsuleComponent->GetScaledCapsuleRadius() * 0.99f;
	FVector TraceEnd = TraceStart - CapsuleComponent->GetUpVector()* (CapsuleHalfHeight - ShapeRadius + GroundHitToleranceDistance + 1.0f);
	FHitResult HitResult;
	TArray<AActor*> ActorsToIgnore;

	
#pragma region Standing/Falling Definition

	/** Testing if the Capsule is in air or standing on a walkable surface*/

	UKismetSystemLibrary::SphereTraceSingle_NEW(this, TraceStart, TraceEnd, ShapeRadius, 
		UEngineTypes::ConvertToTraceType(TraceChannel), true, ActorsToIgnore, DrawDebugType, HitResult, true);
	bIsInAir = !HitResult.bBlockingHit;
	TimeInAir = bIsInAir ? TimeInAir + DeltaTime : 0.0f;
	CurrentStandingSurface = HitResult;

#pragma endregion

#pragma region Update Capsule linearDamping
	/**
	* Update Capsule linearDamping
	* If Grounded L-D is set to 1.0f , in same cases helps to stop the capsule when we are not moving
	* If falling case , stetting L-D to 0.01f , Helps to reach the wanted jump height when JumpImpulse is applied
	*/

	if (CapsuleComponent->GetLinearDamping() != 0.01f && bIsInAir)
	{
		CapsuleComponent->SetLinearDamping(0.01f);
	}
	else if (CapsuleComponent->GetLinearDamping() != 1.0f && !bIsInAir)
	{
		CapsuleComponent->SetLinearDamping(1.0f);
	}
	else if (TimeInAir > 1.0f && PlanetActor != nullptr && !bIsJumping)
	{
		CapsuleComponent->SetLinearDamping(0.5f);
	}
#pragma endregion

#pragma region Gravity Settings

	/*  Gravity Settings : Update Current Gravity info*/

	if (bResetVelocityOnGravitySwitch)
	{
		if (bIsInAir && bCanResetGravity && TimeInAir >= GravitySwitchDelay)
		{
			StopMovementImmediately();
			bCanResetGravity = false;
		}
		else if (!bIsInAir && !bCanResetGravity)
		{
			bCanResetGravity = true;
		}
	}


	if (!bIsInAir && StandingVerticalOrientation == EVerticalOrientation::EVO_SurfaceNormal)
	{

		if (bUseCapsuleHit)
		{
			if (CapsuleHitResult.IsValidBlockingHit())
			{
				CurrentTracedSurface = CapsuleHitResult;
			}
		}

		else
		{
			ShapeRadius = CapsuleComponent->GetScaledCapsuleRadius() * CurrentTraceShapeScale;
			TraceEnd = TraceStart - CapsuleComponent->GetUpVector()* (CapsuleHalfHeight + GroundHitToleranceDistance + 1.0f);

			if (TraceShape == ETraceShape::ETS_Line)
			{
				UKismetSystemLibrary::LineTraceSingle_NEW(this, TraceStart, TraceEnd, 
					UEngineTypes::ConvertToTraceType(TraceChannel), true, ActorsToIgnore, DrawDebugType, HitResult, true);
			}
			else if (TraceShape == ETraceShape::ETS_Sphere)
			{
				TraceEnd += CapsuleComponent->GetUpVector() * ShapeRadius;
				UKismetSystemLibrary::SphereTraceSingle_NEW(this, TraceStart, TraceEnd, ShapeRadius, 
					UEngineTypes::ConvertToTraceType(TraceChannel), true, ActorsToIgnore, DrawDebugType, HitResult, true);
			}
			else
			{
				TraceEnd += CapsuleComponent->GetUpVector() * ShapeRadius;
				UKismetSystemLibrary::BoxTraceSingle(this, TraceStart, TraceEnd, FVector(1, 1, 1)*ShapeRadius, CapsuleComponent->GetComponentRotation(),
					UEngineTypes::ConvertToTraceType(TraceChannel), true, ActorsToIgnore, DrawDebugType, HitResult, true);
			}

			CurrentTracedSurface = HitResult;

		}
		const bool bOnWalkableSurface = CurrentTracedSurface.IsValidBlockingHit();


		if (bOnWalkableSurface)
		{
			SurfaceBasedGravityInfo.GravityDirection = -HitResult.ImpactNormal;
			CurrentGravityInfo = SurfaceBasedGravityInfo;
			CurrentOrientationInfo = OrientationSettings.SurfaceBasedGravity;
		}

	}

	else if ((!bIsInAir && StandingVerticalOrientation == EVerticalOrientation::EVO_GravityDirection) ||
		(bIsInAir && FallingVerticalOrientation == EVerticalOrientation::EVO_GravityDirection))
	{

		if (!bIsInAir || TimeInAir > GravitySwitchDelay)
		{

			switch (CustomGravityType)
			{


			case EGravityType::EGT_Default:
			{
				if (CapsuleComponent->IsGravityEnabled() && GravityScale == 0)
				{
					CapsuleComponent->SetEnableGravity(false);
					CapsuleComponent->SetAllPhysicsLinearVelocity(FVector::ZeroVector);
				}
				else if (!CapsuleComponent->IsGravityEnabled() && GravityScale != 0)
				{
					CapsuleComponent->SetEnableGravity(true);
				}

				CurrentGravityInfo = FGravityInfo(-CapsuleComponent->GetWorld()->GetGravityZ(), -FVector::UpVector, EForceMode::EFM_Acceleration, true);
				CurrentOrientationInfo = OrientationSettings.DefaultGravity;

				UpdateCapsuleRotation(DeltaTime, -CurrentGravityInfo.GravityDirection, CurrentOrientationInfo.bIsInstant, CurrentOrientationInfo.RotationInterpSpeed);

				return;
			}


			case EGravityType::EGT_Custom:
			{
				CurrentGravityInfo = CustomGravityInfo;
				CurrentOrientationInfo = OrientationSettings.CustomGravity;
				break;
			}


			case EGravityType::EGT_GlobalCustom:
			{
				CurrentGravityInfo = UCustomGravityManager::GetGlobalCustomGravityInfo();
				CurrentOrientationInfo = OrientationSettings.GlobalCustomGravity;
				break;
			}


			case EGravityType::EGT_Point:
			{
				if (PlanetActor == NULL) { return; }
				CurrentGravityInfo = PlanetActor->GetGravityinfo(CapsuleComponent->GetComponentLocation());
				CurrentOrientationInfo = OrientationSettings.PointGravity;
				break;
			}
			}
		}
	}

#pragma endregion


	
	/** Variables definition & initialization */
	const FVector CurrentGravityDirection = CurrentGravityInfo.GravityDirection;
	const bool bUseAccelerationChange = (CurrentGravityInfo.ForceMode == EForceMode::EFM_Acceleration);
	const bool bShouldUseStepping = CurrentGravityInfo.bForceSubStepping;
	const float CurrentGravityPower = CurrentGravityInfo.GravityPower * GravityScale;

	const FVector GravityForce = CurrentGravityDirection.GetSafeNormal() * CurrentGravityPower;

	const float InterpSpeed = CurrentOrientationInfo.RotationInterpSpeed;
	const bool bOrientationIsInstant = CurrentOrientationInfo.bIsInstant;

	/* Update Rotation : Orient Capsule's up vector to have the same direction as -gravityDirection */
	UpdateCapsuleRotation(DeltaTime, -CurrentGravityDirection, bOrientationIsInstant, InterpSpeed);

	/* Apply Gravity*/
	ApplyGravity(GravityForce, bShouldUseStepping, bUseAccelerationChange);
}