void UAITask_MoveTo::ConditionalUpdatePath() { // mark this path as waiting for repath so that PathFollowingComponent doesn't abort the move while we // micro manage repathing moment // note that this flag fill get cleared upon repathing end if (Path.IsValid()) { Path->SetManualRepathWaiting(true); } if (MoveRequest.IsUsingPathfinding() && OwnerController && OwnerController->ShouldPostponePathUpdates()) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Log, TEXT("%s> can't path right now, waiting..."), *GetName()); OwnerController->GetWorldTimerManager().SetTimer(PathRetryTimerHandle, this, &UAITask_MoveTo::ConditionalUpdatePath, 0.2f, false); } else { PathRetryTimerHandle.Invalidate(); ANavigationData* NavData = Path.IsValid() ? Path->GetNavigationDataUsed() : nullptr; if (NavData) { NavData->RequestRePath(Path, ENavPathUpdateType::NavigationChanged); } else { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Log, TEXT("%s> unable to repath, aborting!"), *GetName()); FinishMoveTask(EPathFollowingResult::Aborted); } } }
void UGameplayTask::PauseInTaskQueue() { switch (TaskState) { case EGameplayTaskState::Uninitialized: UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Error , TEXT("UGameplayTask::PauseInTaskQueue Task %s passed for pausing withouth having InitTask called on it!") , *GetName()); break; case EGameplayTaskState::AwaitingActivation: // nothing to do here. Don't change the state to indicate this task has never been run before break; case EGameplayTaskState::Paused: // nothing to do here. Already paused break; case EGameplayTaskState::Active: // pause! Pause(); break; case EGameplayTaskState::Finished: // nothing to do here. But sounds odd, so let's log this, just in case UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Log , TEXT("UGameplayTask::PauseInTaskQueue Task %s being pause while already marked as Finished") , *GetName()); break; default: checkNoEntry(); // looks like unhandled value! Probably a new enum entry has been added break; } }
void UGameplayTask::OnGameplayTaskInitialized(UGameplayTask& Task) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose, TEXT("%s> Child task initialized: %s"), *GetName(), *Task.GetName()); // only one child task is allowed if (ChildTask) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose, TEXT(">> terminating previous child task: %s"), *ChildTask->GetName()); ChildTask->EndTask(); } ChildTask = &Task; }
//----------------------------------------------------------------------// // GameplayTasksComponent-related functions //----------------------------------------------------------------------// void UGameplayTask::ActivateInTaskQueue() { switch(TaskState) { case EGameplayTaskState::Uninitialized: UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Error , TEXT("UGameplayTask::ActivateInTaskQueue Task %s passed for activation withouth having InitTask called on it!") , *GetName()); break; case EGameplayTaskState::AwaitingActivation: PerformActivation(); break; case EGameplayTaskState::Paused: // resume Resume(); break; case EGameplayTaskState::Active: // nothing to do here break; case EGameplayTaskState::Finished: // If a task has finished, and it's being revived let's just treat the same as AwaitingActivation PerformActivation(); break; default: checkNoEntry(); // looks like unhandled value! Probably a new enum entry has been added break; } }
void UGameplayTask::ExternalCancel() { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose , TEXT("%s ExternalCancel called, current State: %s") , *GetName(), *GetTaskStateName()); EndTask(); }
void UAITask_MoveTo::Resume() { Super::Resume(); if (!MoveRequestID.IsValid() || !OwnerController->ResumeMove(MoveRequestID)) { UE_CVLOG(MoveRequestID.IsValid(), GetGameplayTasksComponent(), LogGameplayTasks, Log, TEXT("%s> Resume move failed, starting new one."), *GetName()); ConditionalPerformMove(); } }
void UGameplayTask::Resume() { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose , TEXT("%s Resume called, current State: %s") , *GetName(), *GetTaskStateName()); TaskState = EGameplayTaskState::Active; TasksComponent->OnGameplayTaskActivated(*this); }
void UGameplayTask::Pause() { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose , TEXT("%s Pause called, current State: %s") , *GetName(), *GetTaskStateName()); TaskState = EGameplayTaskState::Paused; TasksComponent->OnGameplayTaskDeactivated(*this); }
void UGameplayTask::EndTask() { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose , TEXT("%s EndTask called, current State: %s") , *GetName(), *GetTaskStateName()); if (TaskState != EGameplayTaskState::Finished && !IsPendingKill()) { OnDestroy(false); } }
void UAITask_MoveTo::OnRequestFinished(FAIRequestID RequestID, const FPathFollowingResult& Result) { if (RequestID == MoveRequestID) { if (Result.HasFlag(FPathFollowingResultFlags::UserAbort) && Result.HasFlag(FPathFollowingResultFlags::NewRequest) && !Result.HasFlag(FPathFollowingResultFlags::ForcedScript)) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Log, TEXT("%s> ignoring OnRequestFinished, move was aborted by new request"), *GetName()); } else { // reset request Id, FinishMoveTask doesn't need to update path following's state MoveRequestID = FAIRequestID::InvalidRequest; FinishMoveTask(Result.Code); } } else if (IsActive()) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Warning, TEXT("%s> received OnRequestFinished with not matching RequestID!"), *GetName()); } }
void UGameplayTask::ExternalConfirm(bool bEndTask) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose , TEXT("%s ExternalConfirm called, bEndTask = %s, State : %s") , *GetName(), bEndTask ? TEXT("TRUE") : TEXT("FALSE"), *GetTaskStateName()); if (bEndTask) { EndTask(); } }
void UGameplayTask::OnGameplayTaskDeactivated(UGameplayTask& Task) { // cleanup after deactivation if (&Task == ChildTask) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose, TEXT("%s> Child task deactivated: %s (state: %s)"), *GetName(), *Task.GetName(), *Task.GetTaskStateName()); if (Task.IsFinished()) { ChildTask = nullptr; } } }
void UGameplayTask::TaskOwnerEnded() { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose , TEXT("%s TaskOwnerEnded called, current State: %s") , *GetName(), *GetTaskStateName()); if (TaskState != EGameplayTaskState::Finished && !IsPendingKill()) { bOwnerFinished = true; OnDestroy(true); } }
void UAITask_MoveTo::ConditionalPerformMove() { if (MoveRequest.IsUsingPathfinding() && OwnerController && OwnerController->ShouldPostponePathUpdates()) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Log, TEXT("%s> can't path right now, waiting..."), *GetName()); OwnerController->GetWorldTimerManager().SetTimer(MoveRetryTimerHandle, this, &UAITask_MoveTo::ConditionalPerformMove, 0.2f, false); } else { MoveRetryTimerHandle.Invalidate(); PerformMove(); } }
void UAITask_MoveTo::OnPathEvent(FNavigationPath* InPath, ENavPathEvent::Type Event) { const static UEnum* NavPathEventEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("ENavPathEvent")); UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Log, TEXT("%s> Path event: %s"), *GetName(), *NavPathEventEnum->GetEnumName(Event)); switch (Event) { case ENavPathEvent::NewPath: case ENavPathEvent::UpdatedDueToGoalMoved: case ENavPathEvent::UpdatedDueToNavigationChanged: if (InPath && InPath->IsPartial() && !MoveRequest.IsUsingPartialPaths()) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Log, TEXT(">> partial path is not allowed, aborting")); UPathFollowingComponent::LogPathHelper(OwnerController, InPath, MoveRequest.GetGoalActor()); FinishMoveTask(EPathFollowingResult::Aborted); } #if ENABLE_VISUAL_LOG else if (!IsActive()) { UPathFollowingComponent::LogPathHelper(OwnerController, InPath, MoveRequest.GetGoalActor()); } #endif // ENABLE_VISUAL_LOG break; case ENavPathEvent::Invalidated: ConditionalUpdatePath(); break; case ENavPathEvent::Cleared: case ENavPathEvent::RePathFailed: UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Log, TEXT(">> no path, aborting!")); FinishMoveTask(EPathFollowingResult::Aborted); break; case ENavPathEvent::MetaPathUpdate: default: break; } }
void UGameplayTask::Resume() { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose , TEXT("%s Resume called, current State: %s") , *GetName(), *GetTaskStateName()); TaskState = EGameplayTaskState::Active; TasksComponent->OnTaskActivated(*this); if (bOwnedByTasksComponent == false && TaskOwner.IsValid()) { TaskOwner->OnTaskActivated(*this); } }
void UGameplayTask::PerformActivation() { if (TaskState == EGameplayTaskState::Active) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Warning , TEXT("%s PerformActivation called while TaskState is already Active. Bailing out.") , *GetName()); return; } TaskState = EGameplayTaskState::Active; Activate(); TasksComponent->OnGameplayTaskActivated(*this); }
void UAITask_MoveTo::PerformMove() { UPathFollowingComponent* PFComp = OwnerController ? OwnerController->GetPathFollowingComponent() : nullptr; if (PFComp == nullptr) { FinishMoveTask(EPathFollowingResult::Invalid); return; } ResetObservers(); ResetTimers(); // start new move request FNavPathSharedPtr FollowedPath; const FPathFollowingRequestResult ResultData = OwnerController->MoveTo(MoveRequest, &FollowedPath); switch (ResultData.Code) { case EPathFollowingRequestResult::Failed: FinishMoveTask(EPathFollowingResult::Invalid); break; case EPathFollowingRequestResult::AlreadyAtGoal: MoveRequestID = ResultData.MoveId; OnRequestFinished(ResultData.MoveId, FPathFollowingResult(EPathFollowingResult::Success, FPathFollowingResultFlags::AlreadyAtGoal)); break; case EPathFollowingRequestResult::RequestSuccessful: MoveRequestID = ResultData.MoveId; PathFinishDelegateHandle = PFComp->OnRequestFinished.AddUObject(this, &UAITask_MoveTo::OnRequestFinished); SetObservedPath(FollowedPath); if (TaskState == EGameplayTaskState::Finished) { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Error, TEXT("%s> re-Activating Finished task!"), *GetName()); } break; default: checkNoEntry(); break; } }
void UAITask_MoveTo::HandleMoveFinished(FAIRequestID RequestID, EPathFollowingResult::Type Result) { if (RequestID == MoveRequestID) { if (Result == EPathFollowingResult::Success) { EndTask(); OnMoveFinished.Broadcast(Result); } else { Pause(); } } else { // @todo report issue to the owner component UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Warning, TEXT("%s got movement-finished-notification but RequestID doesn't match. Possible task leak"), *GetName()); } }
UGameplayTasksComponent* UGameplayTask::GetGameplayTasksComponent(const UGameplayTask& Task) const { return ((&Task == ChildTask) || (&Task == this)) ? GetGameplayTasksComponent() : nullptr; }
void UGameplayTask::Activate() { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose , TEXT("%s Activate called, current State: %s") , *GetName(), *GetTaskStateName()); }