bool UHoatCameraModifierFocusTargetActor::ProcessViewRotation(class AActor* ViewTarget, float DeltaTime,
                                                                FRotator& OutViewRotation, FRotator& OutDeltaRot)
{
    Super::ProcessViewRotation(ViewTarget, DeltaTime, OutViewRotation, OutDeltaRot);

    // Check if we're selecting a target.
    if (!IsValid(ViewTarget))
    {
        return false;
    }

	ITargetingActorInterface* targetingActor = Cast<ITargetingActorInterface>(ViewTarget);

    if (!targetingActor)
    {
        return false;
    }

    if (!targetingActor->IsSelectingTarget())
    {
        return false;
    }

    // Check if there's a selected target.
    AActor* currentTarget = targetingActor->GetCurrentTarget();

    if (IsValid(currentTarget))
    {
        if (currentTarget != LastTarget)
        {
            // We have selected a new target. Compute desired rotation.
            FVector cameraLocation = CameraOwner->GetCameraLocation();
            FVector targetLocation = currentTarget->GetActorLocation();

            // Get rotation delta from current camera rotation to look-at rotation for the target.
            // As the camera position might change depending on its rotation (e.g. for spring arms),
            // we just compute this once per target and store the result.
            // Otherwise, for very close targets, we risk rotating the camera back and forth as its position changes.
            DesiredRotation = UKismetMathLibrary::FindLookAtRotation(cameraLocation, targetLocation);
            LastTarget = currentTarget;
        }

        FRotator currentRotation = OutViewRotation;

        if (SnapSpeed <= 0)
        {
            // Snap immediately.
            OutViewRotation = DesiredRotation;
        }
        else
        {
            FRotator towardsDesired = DesiredRotation - currentRotation;
            FRotator towardsDesiredNormalized = towardsDesired.GetNormalized();

            if (towardsDesiredNormalized.IsNearlyZero())
            {
                // Prevent overshooting.
                OutViewRotation = DesiredRotation;
            }
            else
            {
                // Apply rotation speed.
                FRotator deltaRot = towardsDesiredNormalized * SnapSpeed * DeltaTime;
                OutDeltaRot += deltaRot;
            }
        }
    }
    else
    {
        LastTarget = nullptr;

        // No target selected. Smoothly apply player input.
        FVector2D targetSelectionInput = targetingActor->GetCurrentTargetSelectionInput();

        FRotator deltaRot;
        deltaRot.Yaw = targetSelectionInput.X * RotationSpeed * DeltaTime;
        deltaRot.Pitch = -targetSelectionInput.Y * RotationSpeed * DeltaTime;
        deltaRot.Roll = 0.0f;

        OutDeltaRot += deltaRot;
    }

    // Prevent further camera modifiers from being applied.
    return true;
}
void UArchVisCharMovementComponent::PhysWalking(float DeltaTime, int32 Iterations)
{
	// let character do its thing for translation
	Super::PhysWalking(DeltaTime, Iterations);

	//
	// now we will handle rotation
	//

	// update yaw
	if (CurrentRotInput.Yaw == 0)
	{
		// decelerate to 0
		if (CurrentRotationalVelocity.Yaw > 0.f)
		{
			CurrentRotationalVelocity.Yaw -= RotationalDeceleration.Yaw * DeltaTime;
			CurrentRotationalVelocity.Yaw = FMath::Max(CurrentRotationalVelocity.Yaw, 0.f);		// don't go below 0 because that would be re-accelerating the other way
		}
		else
		{
			CurrentRotationalVelocity.Yaw += RotationalDeceleration.Yaw * DeltaTime;
			CurrentRotationalVelocity.Yaw = FMath::Min(CurrentRotationalVelocity.Yaw, 0.f);		// don't go above 0 because that would be re-accelerating the other way
		}
	}
	else
	{
		// accelerate in desired direction
		// clamp delta so it won't take us outside the acceptable speed range
		// note that if we're already out of that range, we won't clamp back
		float const MaxYawVelMag = FMath::Min(1.f, FMath::Abs(CurrentRotInput.Yaw)) * MaxRotationalVelocity.Yaw;
		float const MaxDeltaYawVel = FMath::Max(0.f, MaxYawVelMag - CurrentRotationalVelocity.Yaw);
		float const MinDeltaYawVel = FMath::Min(0.f, -(CurrentRotationalVelocity.Yaw + MaxYawVelMag));
		float const DeltaYaw = FMath::Clamp(CurrentRotInput.Yaw * RotationalAcceleration.Yaw * DeltaTime, MinDeltaYawVel, MaxDeltaYawVel);
		CurrentRotationalVelocity.Yaw += DeltaYaw;
	}

	// update pitch
	if (CurrentRotInput.Pitch == 0)
	{
		// decelerate to 0
		if (CurrentRotationalVelocity.Pitch > 0.f)
		{
			CurrentRotationalVelocity.Pitch -= RotationalDeceleration.Pitch * DeltaTime;
			CurrentRotationalVelocity.Pitch = FMath::Max(CurrentRotationalVelocity.Pitch, 0.f);		// don't go below 0 because that would be reaccelerating the other way
		}
		else
		{
			CurrentRotationalVelocity.Pitch += RotationalDeceleration.Pitch * DeltaTime;
			CurrentRotationalVelocity.Pitch = FMath::Min(CurrentRotationalVelocity.Pitch, 0.f);		// don't go above 0 because that would be reaccelerating the other way
		}
	}
	else
	{
		float const MaxPitchVelMag = FMath::Min(1.f, FMath::Abs(CurrentRotInput.Pitch)) * MaxRotationalVelocity.Pitch;
		float const MaxDeltaPitchVel = FMath::Max(0.f, MaxPitchVelMag - CurrentRotationalVelocity.Pitch);
		float const MinDeltaPitchVel = FMath::Min(0.f, -(CurrentRotationalVelocity.Pitch + MaxPitchVelMag));
		float const DeltaPitch = FMath::Clamp(CurrentRotInput.Pitch * RotationalAcceleration.Pitch * DeltaTime, MinDeltaPitchVel, MaxDeltaPitchVel);
		CurrentRotationalVelocity.Pitch += DeltaPitch;
	}

	// apply rotation
	FRotator RotDelta = CurrentRotationalVelocity * DeltaTime;
	if (!RotDelta.IsNearlyZero())
	{
		FRotator const CurrentComponentRot = UpdatedComponent->GetComponentRotation();

		// enforce pitch limits
		float const CurrentPitch = CurrentComponentRot.Pitch;
		float const MinDeltaPitch = MinPitch - CurrentPitch;
		float const MaxDeltaPitch = MaxPitch - CurrentPitch;
		float const OldPitch = RotDelta.Pitch;
		RotDelta.Pitch = FMath::Clamp(RotDelta.Pitch, MinDeltaPitch, MaxDeltaPitch);
		if (OldPitch != RotDelta.Pitch)
		{
			// if we got clamped, zero the pitch velocity
			CurrentRotationalVelocity.Pitch = 0.f;
		}

		FRotator const NewRot = CurrentComponentRot + RotDelta;

		FHitResult Hit(1.f);
		SafeMoveUpdatedComponent(FVector::ZeroVector, NewRot, false, Hit);
	}

	// consume input
	CurrentRotInput = FRotator::ZeroRotator;
}