void UNavigationPath::SetPath(FNavPathSharedPtr NewSharedPath) { FNavigationPath* NewPath = NewSharedPath.Get(); if (SharedPath.Get() != NewPath) { if (SharedPath.IsValid()) { SharedPath->RemoveObserver(PathObserverDelegateHandle); } SharedPath = NewSharedPath; if (NewPath != NULL) { PathObserverDelegateHandle = NewPath->AddObserver(PathObserver); if (RecalculateOnInvalidation != ENavigationOptionFlag::Default) { NewPath->EnableRecalculationOnInvalidation(RecalculateOnInvalidation == ENavigationOptionFlag::Enable); } SetPathPointsFromPath(*NewPath); } else { PathPoints.Reset(); } OnPathEvent(NewPath, NewPath != NULL ? ENavPathEvent::NewPath : ENavPathEvent::Cleared); } }
void UNavigationComponent::SetPath(const FNavPathSharedPtr& ResultPath) { check(ResultPath.Get() != NULL); Path = ResultPath; Path->SetObserver(PathObserverDelegate); bIsPathPartial = Path->IsPartial(); }
void UNavigationComponent::AsyncGeneratePath_OnCompleteCallback(uint32 QueryID, ENavigationQueryResult::Type Result, FNavPathSharedPtr ResultPath) { if (QueryID != uint32(AsynPathQueryID)) { UE_VLOG(GetOwner(), LogNavigation, Display, TEXT("Pathfinding query %u finished, but it's different from AsynPathQueryID (%d)"), QueryID, AsynPathQueryID); return; } check(GetOuter() != NULL); if (Result == ENavigationQueryResult::Success && ResultPath.IsValid() && ResultPath->IsValid()) { const bool bIsSamePath = Path.IsValid() == true && ((const FNavMeshPath*)Path.Get())->ContainsWithSameEnd((const FNavMeshPath*)ResultPath.Get()) && FVector::DistSquared(Path->GetDestinationLocation(), ResultPath->GetDestinationLocation()) < KINDA_SMALL_NUMBER; if (bIsSamePath == false) { if (IsFollowing() == true) { // make sure ticking is enabled (and it shouldn't be enabled before _first_ async path finding) SetComponentTickEnabledAsync(true); } SetPath(ResultPath); CurrentGoal = ResultPath->PathPoints[ ResultPath->PathPoints.Num() - 1 ].Location; NotifyPathUpdate(); } else { UE_VLOG(GetOwner(), LogNavigation, Display, TEXT("Skipping newly generated path due to it being the same as current one")); } } else { ResetTransientData(); if (MyPathObserver != NULL) { MyPathObserver->OnPathFailed(this); } } }
void ANavigationData::TickActor(float DeltaTime, enum ELevelTick TickType, FActorTickFunction& ThisTickFunction) { Super::TickActor(DeltaTime, TickType, ThisTickFunction); PurgeUnusedPaths(); INC_DWORD_STAT_BY(STAT_Navigation_ObservedPathsCount, ObservedPaths.Num()); if (NextObservedPathsTickInSeconds >= 0.f) { NextObservedPathsTickInSeconds -= DeltaTime; if (NextObservedPathsTickInSeconds <= 0.f) { RepathRequests.Reserve(ObservedPaths.Num()); for (int32 PathIndex = ObservedPaths.Num() - 1; PathIndex >= 0; --PathIndex) { if (ObservedPaths[PathIndex].IsValid()) { FNavPathSharedPtr SharedPath = ObservedPaths[PathIndex].Pin(); FNavigationPath* Path = SharedPath.Get(); EPathObservationResult::Type Result = Path->TickPathObservation(); switch (Result) { case EPathObservationResult::NoLongerObserving: ObservedPaths.RemoveAtSwap(PathIndex, 1, /*bAllowShrinking=*/false); break; case EPathObservationResult::NoChange: // do nothing break; case EPathObservationResult::RequestRepath: RepathRequests.Add(FNavPathRecalculationRequest(SharedPath, ENavPathUpdateType::GoalMoved)); break; default: check(false && "unhandled EPathObservationResult::Type in ANavigationData::TickActor"); break; } } else { ObservedPaths.RemoveAtSwap(PathIndex, 1, /*bAllowShrinking=*/false); } } if (ObservedPaths.Num() > 0) { NextObservedPathsTickInSeconds = ObservedPathsTickInterval; } } } if (RepathRequests.Num() > 0) { float TimeStamp = GetWorldTimeStamp(); TArray<FNavPathRecalculationRequest> PostponedRequests; const UWorld* World = GetWorld(); // @todo batch-process it! for (auto RecalcRequest : RepathRequests) { // check if it can be updated right now FNavPathSharedPtr PinnedPath = RecalcRequest.Path.Pin(); if (PinnedPath.IsValid() == false) { continue; } const UObject* PathQuerier = PinnedPath->GetQuerier(); const INavAgentInterface* PathNavAgent = Cast<const INavAgentInterface>(PathQuerier); if (PathNavAgent && PathNavAgent->ShouldPostponePathUpdates()) { PostponedRequests.Add(RecalcRequest); continue; } FPathFindingQuery Query(PinnedPath.ToSharedRef()); // @todo consider supplying NavAgentPropertied from path's querier const FPathFindingResult Result = FindPath(FNavAgentProperties(), Query.SetPathInstanceToUpdate(PinnedPath)); // update time stamp to give observers any means of telling if it has changed PinnedPath->SetTimeStamp(TimeStamp); // partial paths are still valid and can change to full path when moving goal gets back on navmesh if (Result.IsSuccessful() || Result.IsPartial()) { PinnedPath->UpdateLastRepathGoalLocation(); PinnedPath->DoneUpdating(RecalcRequest.Reason); if (RecalcRequest.Reason == ENavPathUpdateType::NavigationChanged) { RegisterActivePath(PinnedPath); } } else { PinnedPath->RePathFailed(); } } RepathRequests.Reset(); RepathRequests.Append(PostponedRequests); } }