Vault code
bool UCustomCharacterMovementComponent::TryVault()
{
	// Location of the base of the capsule
	FVector BaseLocation = UpdatedComponent->GetComponentLocation() + FVector::DownVector * GetCapsuleHalfHeight();
	// Forward vector
	FVector Forward = UpdatedComponent->GetForwardVector().GetSafeNormal2D();
	// Actors to ignore
	auto Params = MainCharacter->GetIgnoreCharacterParams();

	FHitResult FrontHit;

	// Scale the distance in which we check for a possible hit with the velocity of the character
	float CheckDistance = FMath::Clamp(Velocity | Forward, GetCapsuleRadius() + 30, VaultMaxDistanceCheck);
	
	// The starting point of the line trace takes into account the step height and a customisable offset
	FVector FrontStart = BaseLocation + FVector::UpVector * (MaxStepHeight - 1);

	for (int i = 0; i < 10; i++)
	{
		DRAW_LINE(FrontStart, FrontStart + Forward * CheckDistance, FColor::Yellow)

		if (GetWorld()->LineTraceSingleByProfile(FrontHit, FrontStart, FrontStart + Forward * CheckDistance,
		 "BlockAll", Params)) break;

		FrontStart += FVector::UpVector * (GetCapsuleHalfHeight() - (MaxStepHeight - 1)) / 6;
	}

	if (!FrontHit.IsValidBlockingHit()) return false;

	DRAW_POINT(FrontHit.Location, FColor::Red)

	// CHECK OBSTACLE HEIGHT
	
	TArray<FHitResult> HeightHits;
	FHitResult SurfaceHit; 

	// Project the UP vector onto the normal vector of the object hit and normalize it
		// This give us a vector that goes UP in the direction of the wall

	FVector WallUpVector = FVector::VectorPlaneProject(FVector::UpVector, FrontHit.Normal).GetSafeNormal();

	FVector TraceStart = FrontHit.Location + Forward + WallUpVector * (VaultMaxPossibleHeight - (MaxStepHeight - 1));
	DRAW_LINE(TraceStart, FrontHit.Location + Forward, FColor::Orange);

	if(!GetWorld()->LineTraceMultiByProfile(HeightHits, TraceStart, FrontHit.Location + Forward, "BlockAll", Params))
	{
		return false;
	} 

	for(const FHitResult& Hit : HeightHits)
	{
		// The tag is for the level designer to specify specific objects that should not be "vaultable"
		if (Hit.IsValidBlockingHit() && !Hit.GetActor()->ActorHasTag("NotVault"))
		{
			SurfaceHit = Hit;
			break;
		}
	}

	float Height = (SurfaceHit.Location - BaseLocation) | FVector::UpVector;

	PRINT_SCREEN(FString::Printf(TEXT("Height: %f"), Height));

	DRAW_POINT(SurfaceHit.Location, FColor::Blue);

	if (Height > VaultMaxPossibleHeight) return false;

	// CHECK CLEARANCE

	// The point the capsule should pass while vaulting
	FVector ClearanceCapsuleLocation = SurfaceHit.Location + Forward * GetCapsuleRadius()
	 + FVector::UpVector * GetCapsuleHalfHeight();

	FCollisionShape CapsuleShape = FCollisionShape::MakeCapsule(GetCapsuleRadius(), GetCapsuleHalfHeight());

	if (GetWorld()->OverlapAnyTestByProfile(ClearanceCapsuleLocation, FQuat::Identity, "BlockAll", CapsuleShape, Params))
	{
		DRAW_CAPSULE(ClearanceCapsuleLocation, FColor::Red)
		return false;
	}

	// Check if there are any obstacles between the player and the final point
	if (GetWorld()->OverlapAnyTestByProfile(GetActorLocation() + FVector::UpVector * (GetCapsuleHalfHeight()),
	 FQuat::Identity, "BlockAll", CapsuleShape, Params))
	{
		DRAW_CAPSULE(ClearanceCapsuleLocation, FColor::Black)
		return false;
	}
	
	FVector CapsuleFinalLocationOffset = SurfaceHit.Location + Forward * (GetCapsuleRadius() + VaultMaxPossibleWidth)
	 + FVector::UpVector * (GetCapsuleHalfHeight() / 2);

	// Check if there is enough space on the other side of the obstacle
	if (GetWorld()->OverlapAnyTestByProfile(CapsuleFinalLocationOffset, FQuat::Identity, "BlockAll", CapsuleShape, Params))
	{
		DRAW_CAPSULE(CapsuleFinalLocationOffset, FColor::Silver)
		return false;
	}

	// If on the other side of the object the ground is at a similar height than the starting point
	FHitResult GroundHit;
	TArray<AActor*> ActorsToIgnore;
	VaultMiddleLocation = ClearanceCapsuleLocation - Forward * GetCapsuleRadius();

	if (UKismetSystemLibrary::CapsuleTraceSingleByProfile(GetWorld(), CapsuleFinalLocationOffset,
	 CapsuleFinalLocationOffset + FVector::DownVector * (GetCapsuleHalfHeight() / 2  + 15),
	 GetCapsuleRadius(), GetCapsuleHalfHeight(), "BlockAll", false, 
	 ActorsToIgnore, EDrawDebugTrace::None ,GroundHit, true))
	{
		bFallingVault = false;
		DRAW_CAPSULE(VaultMiddleLocation, FColor::Purple)
		VaultLocation = GroundHit.Location;
	}
	else
	{
		if (Velocity.IsZero()) return false;
		bFallingVault = true;
		VaultLocation = CapsuleFinalLocationOffset;
		DRAW_CAPSULE(VaultLocation, FColor::Blue)
	}
	
	bCanVault = true;
	return true;
}