void UAbilityTask_ApplyRootMotionMoveToActorForce::TickTask(float DeltaTime) { if (bIsFinished) { return; } Super::TickTask(DeltaTime); AActor* MyActor = GetAvatarActor(); if (MyActor) { float CurrentTime = GetWorld()->GetTimeSeconds(); const bool bTimedOut = CurrentTime >= EndTime; // Update target location { const FVector PreviousTargetLocation = TargetLocation; if (UpdateTargetLocation(DeltaTime)) { SetRootMotionTargetLocation(TargetLocation); } else { // TargetLocation not updated - TargetActor not around anymore, continue on to last set TargetLocation } } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) // Draw debug if (DebugMoveToActorForce > 0) { DrawDebugSphere(GetWorld(), TargetLocation, 50.f, 10, FColor::Green, false, 15.f); } #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) const float ReachedDestinationDistanceSqr = 50.f * 50.f; const bool bReachedDestination = FVector::DistSquared(TargetLocation, MyActor->GetActorLocation()) < ReachedDestinationDistanceSqr; if (bTimedOut || (bReachedDestination && !bDisableDestinationReachedInterrupt)) { // Task has finished bIsFinished = true; if (!bIsSimulating) { MyActor->ForceNetUpdate(); OnFinished.Broadcast(bReachedDestination, bTimedOut, TargetLocation); EndTask(); } } } else { bIsFinished = true; EndTask(); } }
//TODO: This is still an awful way to do this and we should scrap this task or do it right. void UAbilityTask_MoveToLocation::TickTask(float DeltaTime) { if (bIsFinished) { return; } Super::TickTask(DeltaTime); AActor* MyActor = GetAvatarActor(); if (MyActor) { ACharacter* MyCharacter = Cast<ACharacter>(MyActor); if (MyCharacter) { UCharacterMovementComponent* CharMoveComp = Cast<UCharacterMovementComponent>(MyCharacter->GetMovementComponent()); if (CharMoveComp) { CharMoveComp->SetMovementMode(MOVE_Custom, 0); } } float CurrentTime = GetWorld()->GetTimeSeconds(); if (CurrentTime >= TimeMoveWillEnd) { bIsFinished = true; // Teleport in attempt to find a valid collision spot MyActor->TeleportTo(TargetLocation, MyActor->GetActorRotation()); if (!bIsSimulating) { MyActor->ForceNetUpdate(); OnTargetLocationReached.Broadcast(); EndTask(); } } else { float MoveFraction = (CurrentTime - TimeMoveStarted) / DurationOfMovement; if (LerpCurve) { MoveFraction = LerpCurve->GetFloatValue(MoveFraction); } MyActor->SetActorLocation(FMath::Lerp<FVector, float>(StartLocation, TargetLocation, MoveFraction)); } } else { bIsFinished = true; EndTask(); } }
void UAbilityTask_WaitAttributeChange::OnAttributeChange(float NewValue, const FGameplayEffectModCallbackData* Data) { if (Data == nullptr) { // There may be no execution data associated with this change, for example a GE being removed. // In this case, we auto fail any WithTag requirement and auto pass any WithoutTag requirement if (WithTag.IsValid()) { return; } } else { if ((WithTag.IsValid() && !Data->EvaluatedData.Tags.HasTag(WithTag, EGameplayTagMatchType::IncludeParentTags, EGameplayTagMatchType::Explicit)) || (WithoutTag.IsValid() && Data->EvaluatedData.Tags.HasTag(WithoutTag, EGameplayTagMatchType::IncludeParentTags, EGameplayTagMatchType::Explicit))) { // Failed tag check return; } } OnChange.Broadcast(); EndTask(); }
void UAbilityTask_WaitGameplayEffectRemoved::Activate() { if (Handle.IsValid() == false) { InvalidHandle.Broadcast(); EndTask(); return;; } UAbilitySystemComponent* EffectOwningAbilitySystemComponent = Handle.GetOwningAbilitySystemComponent(); if (EffectOwningAbilitySystemComponent) { FOnActiveGameplayEffectRemoved* DelPtr = EffectOwningAbilitySystemComponent->OnGameplayEffectRemovedDelegate(Handle); if (DelPtr) { OnGameplayEffectRemovedDelegateHandle = DelPtr->AddUObject(this, &UAbilityTask_WaitGameplayEffectRemoved::OnGameplayEffectRemoved); Registered = true; } } if (!Registered) { // GameplayEffect was already removed, treat this as a warning? Could be cases of immunity or chained gameplay rules that would instant remove something OnGameplayEffectRemoved(); } }
void UAbilityTask_VisualizeTargeting::Activate() { // Need to handle case where target actor was passed into task if (Ability && (TargetClass == NULL)) { if (TargetActor.IsValid()) { AGameplayAbilityTargetActor* SpawnedActor = TargetActor.Get(); TargetClass = SpawnedActor->GetClass(); if (ShouldSpawnTargetActor()) { InitializeTargetActor(SpawnedActor); FinalizeTargetActor(SpawnedActor); } else { TargetActor = NULL; // We may need a better solution here. We don't know the target actor isn't needed till after it's already been spawned. SpawnedActor->Destroy(); SpawnedActor = nullptr; } } else { EndTask(); } } }
void UAbilityTask_WaitGameplayEffectApplied::OnApplyGameplayEffectCallback(UAbilitySystemComponent* Target, const FGameplayEffectSpec& SpecApplied, FActiveGameplayEffectHandle ActiveHandle) { bool PassedComparison = false; AActor* AvatarActor = Target ? Target->AvatarActor : nullptr; if (!Filter.FilterPassesForActor(AvatarActor)) { return; } if (!SourceTagRequirements.RequirementsMet(*SpecApplied.CapturedSourceTags.GetAggregatedTags())) { return; } if (!TargetTagRequirements.RequirementsMet(*SpecApplied.CapturedTargetTags.GetAggregatedTags())) { return; } FGameplayEffectSpecHandle SpecHandle(new FGameplayEffectSpec(SpecApplied)); BroadcastDelegate(AvatarActor, SpecHandle, ActiveHandle); if (TriggerOnce) { EndTask(); } }
/** Valid TargetData was replicated to use (we are server, was sent from client) */ void UAbilityTask_WaitTargetData::OnTargetDataReplicatedCallback(FGameplayAbilityTargetDataHandle Data, FGameplayTag ActivationTag) { check(AbilitySystemComponent); AbilitySystemComponent->ConsumeClientReplicatedTargetData(GetAbilitySpecHandle(), GetActivationPredictionKey()); /** * Call into the TargetActor to sanitize/verify the data. If this returns false, we are rejecting * the replicated target data and will treat this as a cancel. * * This can also be used for bandwidth optimizations. OnReplicatedTargetDataReceived could do an actual * trace/check/whatever server side and use that data. So rather than having the client send that data * explicitly, the client is basically just sending a 'confirm' and the server is now going to do the work * in OnReplicatedTargetDataReceived. */ if (TargetActor && !TargetActor->OnReplicatedTargetDataReceived(Data)) { Cancelled.Broadcast(Data); } else { ValidData.Broadcast(Data); } if (ConfirmationType != EGameplayTargetingConfirmation::CustomMulti) { EndTask(); } }
/** The TargetActor we spawned locally has called back with valid target data */ void UAbilityTask_WaitTargetData::OnTargetDataReadyCallback(FGameplayAbilityTargetDataHandle Data) { check(AbilitySystemComponent); if (!Ability) { return; } FScopedPredictionWindow ScopedPrediction(AbilitySystemComponent, ShouldReplicateDataToServer()); const FGameplayAbilityActorInfo* Info = Ability->GetCurrentActorInfo(); if (IsPredictingClient()) { if (!TargetActor->ShouldProduceTargetDataOnServer) { FGameplayTag ApplicationTag; // Fixme: where would this be useful? AbilitySystemComponent->ServerSetReplicatedTargetData(GetAbilitySpecHandle(), GetActivationPredictionKey(), Data, ApplicationTag, AbilitySystemComponent->ScopedPredictionKey); } else if (ConfirmationType == EGameplayTargetingConfirmation::UserConfirmed) { // We aren't going to send the target data, but we will send a generic confirmed message. AbilitySystemComponent->ServerSetReplicatedEvent(EAbilityGenericReplicatedEvent::GenericConfirm, GetAbilitySpecHandle(), GetActivationPredictionKey(), AbilitySystemComponent->ScopedPredictionKey); } } ValidData.Broadcast(Data); if (ConfirmationType != EGameplayTargetingConfirmation::CustomMulti) { EndTask(); } }
void UAbilityTask::ExternalConfirm(bool bEndTask) { if (bEndTask) { EndTask(); } }
/** Client canceled this Targeting Task (we are the server) */ void UAbilityTask_WaitTargetData::OnTargetDataReplicatedCancelledCallback() { check(AbilitySystemComponent.IsValid()); Cancelled.Broadcast(FGameplayAbilityTargetDataHandle()); EndTask(); }
void UGameplayTask::ExternalCancel() { UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose , TEXT("%s ExternalCancel called, current State: %s") , *GetName(), *GetTaskStateName()); EndTask(); }
/** The TargetActor we spawned locally has called back with a cancel event (they still include the 'last/best' targetdata but the consumer of this may want to discard it) */ void UAbilityTask_WaitTargetData::OnTargetDataCancelledCallback(FGameplayAbilityTargetDataHandle Data) { check(AbilitySystemComponent.IsValid()); AbilitySystemComponent->ServerSetReplicatedTargetDataCancelled(); Cancelled.Broadcast(Data); EndTask(); }
void UAbilityTask_WaitConfirmCancel::OnCancelCallback() { OnCancel.Broadcast(); if (AbilitySystemComponent.IsValid()) { AbilitySystemComponent->ConsumeAbilityConfirmCancel(); EndTask(); } }
void UAbilityTask_WaitConfirmCancel::OnCancelCallback() { if (AbilitySystemComponent) { AbilitySystemComponent->ConsumeGenericReplicatedEvent(EAbilityGenericReplicatedEvent::GenericCancel, GetAbilitySpecHandle(), GetActivationPredictionKey()); OnCancel.Broadcast(); EndTask(); } }
void UAbilityTask_WaitGameplayTagRemoved::GameplayTagCallback(const FGameplayTag Tag, int32 NewCount) { if (NewCount==0) { Removed.Broadcast(); if(OnlyTriggerOnce) { EndTask(); } } }
void UAbilityTask_WaitAttributeChange::OnAttributeChange(float NewValue, const FGameplayEffectModCallbackData* Data) { if (Data == nullptr) { // There may be no execution data associated with this change, for example a GE being removed. // In this case, we auto fail any WithTag requirement and auto pass any WithoutTag requirement if (WithTag.IsValid()) { return; } } else { if ((WithTag.IsValid() && !Data->EffectSpec.CapturedSourceTags.GetAggregatedTags()->HasTag(WithTag, EGameplayTagMatchType::IncludeParentTags, EGameplayTagMatchType::Explicit)) || (WithoutTag.IsValid() && Data->EffectSpec.CapturedSourceTags.GetAggregatedTags()->HasTag(WithoutTag, EGameplayTagMatchType::IncludeParentTags, EGameplayTagMatchType::Explicit))) { // Failed tag check return; } } bool PassedComparison = true; switch (ComparisonType) { case EWaitAttributeChangeComparison::ExactlyEqualTo: PassedComparison = (NewValue == ComparisonValue); break; case EWaitAttributeChangeComparison::GreaterThan: PassedComparison = (NewValue > ComparisonValue); break; case EWaitAttributeChangeComparison::GreaterThanOrEqualTo: PassedComparison = (NewValue >= ComparisonValue); break; case EWaitAttributeChangeComparison::LessThan: PassedComparison = (NewValue < ComparisonValue); break; case EWaitAttributeChangeComparison::LessThanOrEqualTo: PassedComparison = (NewValue <= ComparisonValue); break; case EWaitAttributeChangeComparison::NotEqualTo: PassedComparison = (NewValue != ComparisonValue); break; default: break; } if (PassedComparison) { OnChange.Broadcast(); if (bTriggerOnce) { EndTask(); } } }
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 UAbilityTask_WaitAbilityCommit::OnAbilityCommit(UGameplayAbility *ActivatedAbility) { if ( (WithTag.IsValid() && !ActivatedAbility->AbilityTags.HasTag(WithTag, EGameplayTagMatchType::IncludeParentTags, EGameplayTagMatchType::Explicit)) || (WithoutTag.IsValid() && ActivatedAbility->AbilityTags.HasTag(WithoutTag, EGameplayTagMatchType::IncludeParentTags, EGameplayTagMatchType::Explicit))) { // Failed tag check return; } OnCommit.Broadcast(ActivatedAbility); EndTask(); }
void UAITask_MoveTo::Activate() { Super::Activate(); FAIMoveRequest MoveRequest = (MoveGoalActor != nullptr) ? FAIMoveRequest(MoveGoalActor) : FAIMoveRequest(RealGoalLocation); MoveRequest.SetAllowPartialPath(bShouldAcceptPartialPath) .SetAcceptanceRadius(MoveAcceptanceRadius) .SetStopOnOverlap(bShouldStopOnOverlap) .SetUsePathfinding(bShouldUsePathfinding); const EPathFollowingRequestResult::Type RequestResult = OwnerController->MoveTo(MoveRequest); switch (RequestResult) { case EPathFollowingRequestResult::Failed: { EndTask(); OnRequestFailed.Broadcast(); } break; case EPathFollowingRequestResult::AlreadyAtGoal: { EndTask(); OnMoveFinished.Broadcast(EPathFollowingResult::Success); } break; case EPathFollowingRequestResult::RequestSuccessful: if (OwnerController->GetPathFollowingComponent()) { MoveRequestID = OwnerController->GetPathFollowingComponent()->GetCurrentRequestId(); OwnerController->GetPathFollowingComponent()->OnMoveFinished.AddUObject(this, &UAITask_MoveTo::HandleMoveFinished); } break; default: checkNoEntry(); break; } }
void UAbilityTask_WaitMovementModeChange::OnMovementModeChange(ACharacter * Character, EMovementMode PrevMovementMode, uint8 PreviousCustomMode) { if (Character) { if (UCharacterMovementComponent *MoveComp = Cast<UCharacterMovementComponent>(Character->GetMovementComponent())) { if (RequiredMode == MOVE_None || MoveComp->MovementMode == RequiredMode) { OnChange.Broadcast(MoveComp->MovementMode); EndTask(); return; } } } }
void UAbilityTask_WaitGameplayTagRemoved::Activate() { UAbilitySystemComponent* ASC = GetTargetASC(); if (ASC && ASC->HasMatchingGameplayTag(Tag) == false) { Removed.Broadcast(); if(OnlyTriggerOnce) { EndTask(); return; } } Super::Activate(); }
void UAbilityTask_WaitOverlap::OnHitCallback(AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) { if(OtherActor) { // Construct TargetData FGameplayAbilityTargetData_SingleTargetHit * TargetData = new FGameplayAbilityTargetData_SingleTargetHit(Hit); // Give it a handle and return FGameplayAbilityTargetDataHandle Handle; Handle.Data.Add(TSharedPtr<FGameplayAbilityTargetData>(TargetData)); OnOverlap.Broadcast(Handle); // We are done. Kill us so we don't keep getting broadcast messages EndTask(); } }
void UAbilityTask_ApplyRootMotionJumpForce::Finish() { bIsFinished = true; if (!bIsSimulating) { AActor* MyActor = GetAvatarActor(); if (MyActor) { MyActor->ForceNetUpdate(); OnFinish.Broadcast(); } } EndTask(); }
void UGameplayTask::ReadyForActivation() { if (TasksComponent.IsValid()) { if (RequiresPriorityOrResourceManagement() == false) { PerformActivation(); } else { TasksComponent->AddTaskReadyForActivation(*this); } } else { EndTask(); } }
/** The TargetActor we spawned locally has called back with valid target data */ void UAbilityTask_WaitTargetData::OnTargetDataReadyCallback(FGameplayAbilityTargetDataHandle Data) { check(AbilitySystemComponent.IsValid()); FScopedPredictionWindow ScopedPrediction(AbilitySystemComponent.Get(), ShouldReplicateDataToServer()); if (ShouldReplicateDataToServer()) { AbilitySystemComponent->ServerSetReplicatedTargetData(Data, AbilitySystemComponent->ScopedPredictionKey); } ValidData.Broadcast(Data); if (ConfirmationType != EGameplayTargetingConfirmation::CustomMulti) { EndTask(); } }
void UAbilityTask_WaitAbilityActivate::OnAbilityActivate(UGameplayAbility* ActivatedAbility) { if (!IncludeTriggeredAbilities && ActivatedAbility->IsTriggered()) { return; } if ((WithTag.IsValid() && !ActivatedAbility->AbilityTags.HasTag(WithTag, EGameplayTagMatchType::IncludeParentTags, EGameplayTagMatchType::Explicit)) || (WithoutTag.IsValid() && ActivatedAbility->AbilityTags.HasTag(WithoutTag, EGameplayTagMatchType::IncludeParentTags, EGameplayTagMatchType::Explicit))) { // Failed tag check return; } OnActivate.Broadcast(ActivatedAbility); EndTask(); }
/** The TargetActor we spawned locally has called back with a cancel event (they still include the 'last/best' targetdata but the consumer of this may want to discard it) */ void UAbilityTask_WaitTargetData::OnTargetDataCancelledCallback(FGameplayAbilityTargetDataHandle Data) { check(AbilitySystemComponent); if (IsPredictingClient()) { if (!TargetActor->ShouldProduceTargetDataOnServer) { AbilitySystemComponent->ServerSetReplicatedTargetDataCancelled(GetAbilitySpecHandle(), GetActivationPredictionKey(), AbilitySystemComponent->ScopedPredictionKey ); } else { // We aren't going to send the target data, but we will send a generic confirmed message. AbilitySystemComponent->ServerSetReplicatedEvent(EAbilityGenericReplicatedEvent::GenericCancel, GetAbilitySpecHandle(), GetActivationPredictionKey(), AbilitySystemComponent->ScopedPredictionKey); } } Cancelled.Broadcast(Data); EndTask(); }
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()); } }
void UAbilityTask_WaitInputRelease::OnReleaseCallback(int32 InputID) { float ElapsedTime = GetWorld()->GetTimeSeconds() - StartTime; if (!Ability.IsValid()) { return; } UGameplayAbility* MyAbility = Ability.Get(); check(MyAbility->IsInstantiated()); if (MyAbility->GetCurrentAbilitySpec()->InputID != InputID) { //This key is for some other ability return; } // We are done. Kill us so we don't keep getting broadcast messages OnRelease.Broadcast(ElapsedTime); EndTask(); }
void UAbilityTask_WaitGameplayEffectStackChange::Activate() { if (Handle.IsValid() == false) { InvalidHandle.Broadcast(Handle, 0, 0); EndTask(); return;; } UAbilitySystemComponent* EffectOwningAbilitySystemComponent = Handle.GetOwningAbilitySystemComponent(); if (EffectOwningAbilitySystemComponent) { FOnActiveGameplayEffectStackChange* DelPtr = EffectOwningAbilitySystemComponent->OnGameplayEffectStackChangeDelegate(Handle); if (DelPtr) { OnGameplayEffectStackChangeDelegateHandle = DelPtr->AddUObject(this, &UAbilityTask_WaitGameplayEffectStackChange::OnGameplayEffectStackChange); Registered = true; } } }