void UVehiclePathFollowingComponent::UpdatePathSegment()
{
#ifdef NDEBUG
	if (Path.IsValid())
	{
		for (int i = 0; i < Path->GetPathPoints().Num(); ++i)
		{
			DrawDebugPoint(GetWorld(), Path->GetPathPoints()[i].Location, 40.0f, FColor::Yellow, false, 0.3f);
		}
	}
#endif

    float DistanceLeft = (
        *Path->GetPathPointLocation(Path->GetPathPoints().Num() - 1)
        - MovementComp->GetActorLocation()
    ).Size();

    if (DistanceLeft < AcceptanceRadius)
    {
        OnSegmentFinished();
        OnPathFinished(EPathFollowingResult::Success);
    }
	UPathFollowingComponent::UpdatePathSegment();
}
void UCrowdFollowingComponent::UpdatePathSegment()
{
	if (!bEnableCrowdSimulation)
	{
		Super::UpdatePathSegment();
		return;
	}

	if (!Path.IsValid() || MovementComp == NULL)
	{
		AbortMove(TEXT("no path"), FAIRequestID::CurrentRequest, true, false, EPathFollowingMessage::NoPath);
		return;
	}

	if (!Path->IsValid())
	{
		if (!Path->IsWaitingForRepath())
		{
			AbortMove(TEXT("no path"), FAIRequestID::CurrentRequest, true, false, EPathFollowingMessage::NoPath);
		}
		return;
	}

	// if agent has control over its movement, check finish conditions
	const bool bCanReachTarget = MovementComp->CanStopPathFollowing();
	if (bCanReachTarget && Status == EPathFollowingStatus::Moving)
	{
		const FVector CurrentLocation = MovementComp->GetActorFeetLocation();
		const FVector GoalLocation = GetCurrentTargetLocation();

		if (bCollidedWithGoal)
		{
			// check if collided with goal actor
			OnSegmentFinished();
			OnPathFinished(EPathFollowingResult::Success);
		}
		else if (bFinalPathPart)
		{
			const FVector ToTarget = (GoalLocation - MovementComp->GetActorFeetLocation());
			const bool bDirectPath = Path->CastPath<FAbstractNavigationPath>() != NULL;
			const float SegmentDot = FVector::DotProduct(ToTarget, bDirectPath ? MovementComp->Velocity : CrowdAgentMoveDirection);
			const bool bMovedTooFar = bCheckMovementAngle && (SegmentDot < 0.0);

			// can't use HasReachedDestination here, because it will use last path point
			// which is not set correctly for partial paths without string pulling
			if (bMovedTooFar || HasReachedInternal(GoalLocation, 0.0f, 0.0f, CurrentLocation, AcceptanceRadius, bStopOnOverlap ? MinAgentRadiusPct : 0.0f))
			{
				UE_VLOG(GetOwner(), LogCrowdFollowing, Log, TEXT("Last path segment finished due to \'%s\'"), bMovedTooFar ? TEXT("Missing Last Point") : TEXT("Reaching Destination"));
				OnPathFinished(EPathFollowingResult::Success);
			}
		}
		else
		{
			// override radius multiplier and switch to next path part when closer than 4x agent radius
			const float NextPartMultiplier = 4.0f;
			const bool bHasReached = HasReachedInternal(GoalLocation, 0.0f, 0.0f, CurrentLocation, 0.0f, NextPartMultiplier);

			if (bHasReached)
			{
				SwitchToNextPathPart();
			}
		}
	}

	// gather location samples to detect if moving agent is blocked
	if (bCanReachTarget && Status == EPathFollowingStatus::Moving)
	{
		const bool bHasNewSample = UpdateBlockDetection();
		if (bHasNewSample && IsBlocked())
		{
			OnPathFinished(EPathFollowingResult::Blocked);
		}
	}
}
void UOrionPathFollowingComponent::FollowPathSegment(float DeltaTime)
{
	if (Controller && Controller->GetPawn())
	{
		/*AOrionDinoPawn *Dino = Cast<AOrionDinoPawn>(Controller->GetPawn());
		if (Dino && Dino->bShouldStopMovement)
		{
			Dino->bShouldStopMovement = false;
			OnPathFinished(EPathFollowingResult::Success);
			return;
		}*/

		AOrionCharacter *Pawn = Cast<AOrionCharacter>(Controller->GetPawn());
		if (Pawn && Pawn->IsFlying())
		{
			if (Controller->bFinishedPath)
				OnPathFinished(EPathFollowingResult::Success);

			if (MovementComp == NULL)//|| !Path.IsValid())
			{
				return;
			}

			float dist = (Pawn->GetActorLocation() - GetCurrentTargetFlyingLocation()).Size();

			if (dist < (Pawn->bLanding ? Pawn->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() + 10.0f : Pawn->FlyingOffset))
			{
				if (Pawn->bLanding)
				{
					Controller->bFinishedLanding = true;
					OnPathFinished(EPathFollowingResult::Success);
				}
				else
				{
					Controller->FlightIndex++;
					if (Controller->FlightIndex >= Controller->FlightPath.Num())
					{
						Controller->bFinishedPath = true;
						OnPathFinished(EPathFollowingResult::Success);
					}
				}
			}
			else if (Controller->FlightIndex + 1 >= Controller->FlightPath.Num() && dist < 2.5f * (Pawn->bLanding ? Pawn->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() + 10.0f : Pawn->FlyingOffset)
				&& (Controller->GetEnemy() == nullptr || (Controller->GetEnemy()->GetActorLocation() - Controller->FlightPath.Last()).Size() > 100.0f))
			{
				Controller->bFinishedPath = true;
				OnPathFinished(EPathFollowingResult::Success);
			}

			CharacterMoveComp->SetMovementMode(MOVE_Flying);

			//const FVector CurrentLocation = MovementComp->IsMovingOnGround() ? MovementComp->GetActorFeetLocation() : MovementComp->GetActorLocation();
			const FVector CurrentLocation = MovementComp->GetActorFeetLocation();
			const FVector CurrentTarget = GetCurrentTargetFlyingLocation();
			FVector MoveVelocity = (CurrentTarget - CurrentLocation) / DeltaTime;

			////const int32 LastSegmentStartIndex = Path->GetPathPoints().Num() - 2;
			////const bool bNotFollowingLastSegment = (MoveSegmentStartIndex < LastSegmentStartIndex);

			PostProcessMove.ExecuteIfBound(this, MoveVelocity);
			MovementComp->RequestDirectMove(MoveVelocity, false);// true);// bNotFollowingLastSegment);
			return;
		}
	}

	if (MovementComp == NULL || !Path.IsValid())
		return;

	//if we need to play a rotate animation before we actually move, do that now
	if (HandleRotation())
		return;

	/*if (Path->IsPartial())
	{
		if (Controller && Controller->GetPawn())
		{
			AOrionCharacter *Pawn = Cast<AOrionCharacter>(Controller->GetPawn());
			if (Pawn)
			{
				Pawn->Jump();
			}
		}

		return;
	}*/

	if (CharacterMoveComp->MovementMode == MOVE_Flying)
		CharacterMoveComp->SetMovementMode(MOVE_Walking);

	Super::FollowPathSegment(DeltaTime);
}