// Copyright Epic Games, Inc. All Rights Reserved. #include "AbilityTask_GrantNearbyInteraction.h" #include "GameFramework/Actor.h" #include "Physics/LyraCollisionChannels.h" #include "Interaction/IInteractableTarget.h" #include "Interaction/InteractionStatics.h" #include "Interaction/InteractionQuery.h" #include "AbilitySystemComponent.h" #include "TimerManager.h" #include "GameFramework/Controller.h" UAbilityTask_GrantNearbyInteraction::UAbilityTask_GrantNearbyInteraction(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { } UAbilityTask_GrantNearbyInteraction* UAbilityTask_GrantNearbyInteraction::GrantAbilitiesForNearbyInteractors(UGameplayAbility* OwningAbility, float InteractionScanRange, float InteractionScanRate) { UAbilityTask_GrantNearbyInteraction* MyObj = NewAbilityTask(OwningAbility); MyObj->InteractionScanRange = InteractionScanRange; MyObj->InteractionScanRate = InteractionScanRate; return MyObj; } void UAbilityTask_GrantNearbyInteraction::Activate() { SetWaitingOnAvatar(); UWorld* World = GetWorld(); World->GetTimerManager().SetTimer(QueryTimerHandle, this, &ThisClass::QueryInteractables, InteractionScanRate, true); } void UAbilityTask_GrantNearbyInteraction::OnDestroy(bool AbilityEnded) { Super::OnDestroy(AbilityEnded); UWorld* World = GetWorld(); World->GetTimerManager().ClearTimer(QueryTimerHandle); } void UAbilityTask_GrantNearbyInteraction::QueryInteractables() { UWorld* World = GetWorld(); AActor* ActorOwner = GetAvatarActor(); if (World && ActorOwner) { FCollisionQueryParams Params(SCENE_QUERY_STAT(UAbilityTask_GrantNearbyInteraction), false); TArray OverlapResults; World->OverlapMultiByChannel(OUT OverlapResults, ActorOwner->GetActorLocation(), FQuat::Identity, Lyra_TraceChannel_Interaction, FCollisionShape::MakeSphere(InteractionScanRange), Params); if (OverlapResults.Num() > 0) { TArray> InteractableTargets; UInteractionStatics::AppendInteractableTargetsFromOverlapResults(OverlapResults, OUT InteractableTargets); FInteractionQuery InteractionQuery; InteractionQuery.RequestingAvatar = ActorOwner; InteractionQuery.RequestingController = Cast(ActorOwner->GetOwner()); TArray Options; for (TScriptInterface& InteractiveTarget : InteractableTargets) { FInteractionOptionBuilder InteractionBuilder(InteractiveTarget, Options); InteractiveTarget->GatherInteractionOptions(InteractionQuery, InteractionBuilder); } // Check if any of the options need to grant the ability to the user before they can be used. for (FInteractionOption& Option : Options) { if (Option.InteractionAbilityToGrant) { // Grant the ability to the GAS, otherwise it won't be able to do whatever the interaction is. FObjectKey ObjectKey(Option.InteractionAbilityToGrant); if (!InteractionAbilityCache.Find(ObjectKey)) { FGameplayAbilitySpec Spec(Option.InteractionAbilityToGrant, 1, INDEX_NONE, this); FGameplayAbilitySpecHandle Handle = AbilitySystemComponent->GiveAbility(Spec); InteractionAbilityCache.Add(ObjectKey, Handle); } } } } } }