void UGameplayTasksComponent::AddTaskToPriorityQueue(UGameplayTask& NewTask) { const bool bStartOnTopOfSamePriority = (NewTask.GetResourceOverlapPolicy() == ETaskResourceOverlapPolicy::StartOnTop); int32 InsertionPoint = INDEX_NONE; for (int32 Idx = 0; Idx < TaskPriorityQueue.Num(); ++Idx) { if (TaskPriorityQueue[Idx] == nullptr) { continue; } if ((bStartOnTopOfSamePriority && TaskPriorityQueue[Idx]->GetPriority() <= NewTask.GetPriority()) || (!bStartOnTopOfSamePriority && TaskPriorityQueue[Idx]->GetPriority() < NewTask.GetPriority())) { TaskPriorityQueue.Insert(&NewTask, Idx); InsertionPoint = Idx; break; } } if (InsertionPoint == INDEX_NONE) { TaskPriorityQueue.Add(&NewTask); } }
void UGameplayTasksComponent::OnGameplayTaskActivated(UGameplayTask& Task) { // process events after finishing all operations FEventLock ScopeEventLock(this); if (Task.IsTickingTask()) { check(TickingTasks.Contains(&Task) == false); TickingTasks.Add(&Task); // If this is our first ticking task, set this component as active so it begins ticking if (TickingTasks.Num() == 1) { UpdateShouldTick(); } } if (Task.IsSimulatedTask()) { check(SimulatedTasks.Contains(&Task) == false); SimulatedTasks.Add(&Task); } IGameplayTaskOwnerInterface* TaskOwner = Task.GetTaskOwner(); if (!Task.IsOwnedByTasksComponent() && TaskOwner) { TaskOwner->OnGameplayTaskActivated(Task); } }
//----------------------------------------------------------------------// // Priority and resources handling //----------------------------------------------------------------------// void UGameplayTasksComponent::AddTaskReadyForActivation(UGameplayTask& NewTask) { UE_VLOG(this, LogGameplayTasks, Log, TEXT("AddTaskReadyForActivation %s"), *NewTask.GetName()); ensure(NewTask.RequiresPriorityOrResourceManagement() == true); TaskEvents.Add(FGameplayTaskEventData(EGameplayTaskEvent::Add, NewTask)); // trigger the actual processing only if it was the first event added to the list if (TaskEvents.Num() == 1 && CanProcessEvents()) { ProcessTaskEvents(); } }
static FString DescribeTaskHelper(const UGameplayTask& TaskOb) { const UObject* OwnerOb = Cast<const UObject>(TaskOb.GetTaskOwner()); return FString::Printf(TEXT("\n {white}%s%s {%s}%s:%d {white}Owner:{yellow}%s {white}Res:{yellow}%s"), *TaskOb.GetName(), TaskOb.GetInstanceName() != NAME_None ? *FString::Printf(TEXT(" {yellow}[%s]"), *TaskOb.GetInstanceName().ToString()) : TEXT(""), TaskOb.IsActive() ? TEXT("green") : TEXT("orange"), *TaskOb.GetTaskStateName(), TaskOb.GetPriority(), *GetNameSafe(OwnerOb), TaskOb.GetRequiredResources().IsEmpty() ? TEXT("None") : *TaskOb.GetRequiredResources().GetDebugDescription()); }
void UGameplayTasksComponent::EndAllResourceConsumingTasksOwnedBy(const IGameplayTaskOwnerInterface& TaskOwner)// , bool bNotifyOwner) { { FEventLock ScopeEventLock(this); // can't reuse FindAllTasksOwnedBy here, it's important to remove from queue immediately for (int32 Idx = TaskPriorityQueue.Num() - 1; Idx >= 0; Idx--) { if (TaskPriorityQueue[Idx] && TaskPriorityQueue[Idx]->GetTaskOwner() == &TaskOwner) { UGameplayTask* Task = TaskPriorityQueue[Idx]; TaskPriorityQueue[Idx] = nullptr; Task->TaskOwnerEnded(); } } } UpdateTaskActivations(); }
void UGameplayTasksComponent::RemoveResourceConsumingTask(UGameplayTask& Task) { UE_VLOG(this, LogGameplayTasks, Log, TEXT("RemoveResourceConsumingTask %s"), *Task.GetName()); TaskEvents.Add(FGameplayTaskEventData(EGameplayTaskEvent::Remove, Task)); // trigger the actual processing only if it was the first event added to the list if (TaskEvents.Num() == 1 && CanProcessEvents()) { ProcessTaskEvents(); } }
void AAIController::UnclaimTaskResource(TSubclassOf<UGameplayTaskResource> ResourceClass) { if (CachedGameplayTasksComponent) { const uint8 ResourceID = UGameplayTaskResource::GetResourceID(ResourceClass); if (ScriptClaimedResources.HasID(ResourceID) == true) { ScriptClaimedResources.RemoveID(ResourceID); UE_VLOG(this, LogGameplayTasks, Log, TEXT("UnclaimTaskResource %s"), *GetNameSafe(*ResourceClass)); UGameplayTask* ResourceTask = CachedGameplayTasksComponent->FindResourceConsumingTaskByName(ResourceClass->GetFName()); if (ResourceTask) { ResourceTask->EndTask(); } UE_CVLOG(ResourceTask == nullptr, this, LogGameplayTasks, Warning, TEXT("UnclaimTaskResource failed to find UGameplayTask_ClaimResource instance")); } } }
//----------------------------------------------------------------------// // UBTTaskNode IGameplayTaskOwnerInterface //----------------------------------------------------------------------// void UBTTaskNode::OnTaskDeactivated(UGameplayTask& Task) { ensure(Task.GetTaskOwner() == this); UBehaviorTreeComponent* BTComp = GetBTComponentForTask(Task); if (BTComp) { // this is a super-default behavior. Specific task will surely like to // handle this themselves, finishing with specific result const EBTTaskStatus::Type Status = BTComp->GetTaskStatus(this); FinishLatentTask(*BTComp, Status == EBTTaskStatus::Aborting ? EBTNodeResult::Aborted : EBTNodeResult::Succeeded); } }
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; } } }
EGameplayTaskRunResult UGameplayTasksComponent::RunGameplayTask(IGameplayTaskOwnerInterface& TaskOwner, UGameplayTask& Task, uint8 Priority, FGameplayResourceSet AdditionalRequiredResources, FGameplayResourceSet AdditionalClaimedResources) { const FText NoneText = FText::FromString(TEXT("None")); if (Task.GetState() == EGameplayTaskState::Paused || Task.GetState() == EGameplayTaskState::Active) { // return as success if already running for the same owner, failure otherwise return Task.GetTaskOwner() == &TaskOwner ? (Task.GetState() == EGameplayTaskState::Paused ? EGameplayTaskRunResult::Success_Paused : EGameplayTaskRunResult::Success_Active) : EGameplayTaskRunResult::Error; } // this is a valid situation if the task has been created via "Construct Object" mechanics if (Task.GetState() == EGameplayTaskState::Uninitialized) { Task.InitTask(TaskOwner, Priority); } Task.AddRequiredResourceSet(AdditionalRequiredResources); Task.AddClaimedResourceSet(AdditionalClaimedResources); Task.ReadyForActivation(); switch (Task.GetState()) { case EGameplayTaskState::AwaitingActivation: case EGameplayTaskState::Paused: return EGameplayTaskRunResult::Success_Paused; break; case EGameplayTaskState::Active: return EGameplayTaskRunResult::Success_Active; break; case EGameplayTaskState::Finished: return EGameplayTaskRunResult::Success_Active; break; } return EGameplayTaskRunResult::Error; }
void UGameplayTasksComponent::OnGameplayTaskDeactivated(UGameplayTask& Task) { // process events after finishing all operations FEventLock ScopeEventLock(this); const bool bIsFinished = (Task.GetState() == EGameplayTaskState::Finished); if (Task.GetChildTask() && bIsFinished) { if (Task.HasOwnerFinished()) { Task.GetChildTask()->TaskOwnerEnded(); } else { Task.GetChildTask()->EndTask(); } } if (Task.IsTickingTask()) { // If we are removing our last ticking task, set this component as inactive so it stops ticking TickingTasks.RemoveSingleSwap(&Task); } if (Task.IsSimulatedTask()) { SimulatedTasks.RemoveSingleSwap(&Task); } // Resource-using task if (Task.RequiresPriorityOrResourceManagement() && bIsFinished) { OnTaskEnded(Task); } IGameplayTaskOwnerInterface* TaskOwner = Task.GetTaskOwner(); if (!Task.IsOwnedByTasksComponent() && !Task.HasOwnerFinished() && TaskOwner) { TaskOwner->OnGameplayTaskDeactivated(Task); } UpdateShouldTick(); }
void UGameplayTasksComponent::RemoveTaskFromPriorityQueue(UGameplayTask& Task) { const int32 RemovedTaskIndex = TaskPriorityQueue.Find(&Task); if (RemovedTaskIndex != INDEX_NONE) { TaskPriorityQueue.RemoveAt(RemovedTaskIndex, 1, /*bAllowShrinking=*/false); } else { // take a note and ignore UE_VLOG(this, LogGameplayTasks, Verbose, TEXT("RemoveTaskFromPriorityQueue for %s called, but it's not in the queue. Might have been already removed"), *Task.GetName()); } }
void UGameplayTasksComponent::OnTaskEnded(UGameplayTask& Task) { ensure(Task.RequiresPriorityOrResourceManagement() == true); RemoveResourceConsumingTask(Task); }
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; }