// Fill out your copyright notice in the Description page of Project Settings.


#include "PlayerBodyAnimInstance.h"

#include "FpsPlayer.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "KismetAnimationLibrary.h"

void UPlayerBodyAnimInstance::NativeInitializeAnimation()
{
	Super::NativeInitializeAnimation();

	OwningPlayer = Cast<AFpsPlayer>(TryGetPawnOwner());
}

void UPlayerBodyAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
	Super::NativeUpdateAnimation(DeltaSeconds);

	// Chez un CLIENT, le mesh arrive par replication et peut commencer a
	// s'animer avant que le pawn soit completement initialise : le Cast du
	// NativeInitialize rend alors nullptr, une fois pour toutes, et le corps de
	// l'ami reste fige en pose de reference pour le reste de la partie. On
	// reessaie donc tant qu'on n'a rien -- le cout est un Cast par frame
	// uniquement pendant les quelques frames ou le pawn manque encore.
	if (!OwningPlayer.IsValid())
	{
		OwningPlayer = Cast<AFpsPlayer>(TryGetPawnOwner());
		if (!OwningPlayer.IsValid())
		{
			return;
		}
	}

	const AFpsPlayer* BodyOwner = OwningPlayer.Get();
	const UCharacterMovementComponent* Movement = BodyOwner->GetCharacterMovement();
	if (!Movement)
	{
		return;
	}

	// Composante horizontale seule : en pleine chute la vitesse verticale
	// depasse largement la vitesse de course, et un BlendSpace indexe dessus
	// jouerait un sprint en l'air.
	const FVector Velocity = BodyOwner->GetVelocity();
	const FVector HorizontalVelocity(Velocity.X, Velocity.Y, 0.f);
	GroundSpeed = HorizontalVelocity.Size();

	// L'acceleration, et pas seulement la vitesse : elle tombe a zero des que la
	// touche est relachee, alors que la vitesse decroit encore pendant tout le
	// freinage. Sans elle le cycle de marche continuerait de tourner sur un
	// personnage qui glisse jusqu'a l'arret.
	bIsMoving = GroundSpeed > MovingSpeedThreshold
		&& !Movement->GetCurrentAcceleration().IsNearlyZero();

	bIsFalling = Movement->IsFalling();

	// Prise telle quelle, sans seuil : c'est le Blueprint qui decide ou placer la
	// bascule saut / chute. Une valeur brute reste une valeur brute -- lui donner
	// un seuil ici, ce serait decider a la place de la machine a etats, et il
	// faudrait recompiler pour le regler.
	VerticalSpeed = Velocity.Z;

	// Les deux etats du pawn, repliques chacun de leur cote : bIsCrouched par le
	// moteur, bIsSprinting par AFpsPlayer. On les lit ici plutot que de deviner
	// l'accroupissement a la hauteur de capsule, qui est en pleine interpolation
	// pendant toute la transition.
	bIsCrouching = BodyOwner->bIsCrouched;
	bIsSprinting = BodyOwner->IsSprinting();

	// Direction relative au CORPS et non a la vitesse du monde : c'est ce que
	// demande un BlendSpace directionnel. GetActorRotation() suffit comme
	// reference parce que bUseControllerRotationYaw garde le corps aligne sur le
	// regard -- sur un jeu a la 3e personne libre, il faudrait la rotation de
	// controle a la place.
	//
	// UKismetAnimationLibrary et pas UAnimInstance::CalculateDirection, depreciee
	// en 5.8 : le calcul est le meme, mais l'ancienne cassera la compilation a la
	// prochaine version du moteur.
	LocomotionDirection = UKismetAnimationLibrary::CalculateDirection(HorizontalVelocity, BodyOwner->GetActorRotation());

	// GetBaseAimRotation et pas GetControlRotation : le second n'existe que sur
	// la machine qui possede le pawn, le premier retombe sur RemoteViewPitch
	// pour les pawns des autres joueurs. NormalizeAxis ramene les 350 degres
	// d'un regard vers le bas a -10, seule forme exploitable par un AimOffset.
	AimPitch = FRotator::NormalizeAxis(BodyOwner->GetBaseAimRotation().Pitch);

	LocomotionPlayRate = FMath::Clamp(
		GroundSpeed / ReferenceLocomotionSpeed,
		MinLocomotionPlayRate,
		MaxLocomotionPlayRate);
}
