2022-05-23 18:41:30 +00:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "LyraAbilitySystemComponent.h"
2022-09-13 07:18:28 +00:00
# include "Abilities/GameplayAbility.h"
# include "Abilities/GameplayAbilityTargetTypes.h"
# include "Abilities/GameplayAbilityTypes.h"
2022-05-23 18:41:30 +00:00
# include "Abilities/LyraGameplayAbility.h"
# include "AbilitySystem/LyraAbilityTagRelationshipMapping.h"
2022-09-13 07:18:28 +00:00
# include "Animation/LyraAnimInstance.h"
# include "Containers/UnrealString.h"
# include "Engine/World.h"
# include "GameFramework/Actor.h"
# include "GameFramework/Pawn.h"
# include "GameplayAbilitySpec.h"
# include "GameplayEffect.h"
# include "GameplayEffectTypes.h"
# include "GameplayTagContainer.h"
# include "HAL/PlatformMath.h"
# include "HAL/UnrealMemory.h"
# include "Logging/LogCategory.h"
# include "Logging/LogMacros.h"
# include "LyraGlobalAbilitySystem.h"
# include "LyraLogChannels.h"
# include "Misc/AssertionMacros.h"
# include "System/LyraAssetManager.h"
# include "System/LyraGameData.h"
# include "Templates/Casts.h"
# include "Templates/SharedPointer.h"
# include "Templates/SubclassOf.h"
# include "Trace/Detail/Channel.h"
# include "UObject/NameTypes.h"
# include "UObject/SoftObjectPtr.h"
# include "UObject/UObjectBaseUtility.h"
# include "UObject/WeakObjectPtr.h"
# include "UObject/WeakObjectPtrTemplates.h"
2022-05-23 18:41:30 +00:00
UE_DEFINE_GAMEPLAY_TAG ( TAG_Gameplay_AbilityInputBlocked , " Gameplay.AbilityInputBlocked " ) ;
ULyraAbilitySystemComponent : : ULyraAbilitySystemComponent ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
{
InputPressedSpecHandles . Reset ( ) ;
InputReleasedSpecHandles . Reset ( ) ;
InputHeldSpecHandles . Reset ( ) ;
FMemory : : Memset ( ActivationGroupCounts , 0 , sizeof ( ActivationGroupCounts ) ) ;
}
void ULyraAbilitySystemComponent : : EndPlay ( const EEndPlayReason : : Type EndPlayReason )
{
if ( ULyraGlobalAbilitySystem * GlobalAbilitySystem = UWorld : : GetSubsystem < ULyraGlobalAbilitySystem > ( GetWorld ( ) ) )
{
GlobalAbilitySystem - > UnregisterASC ( this ) ;
}
2022-09-13 07:18:28 +00:00
Super : : EndPlay ( EndPlayReason ) ;
2022-05-23 18:41:30 +00:00
}
void ULyraAbilitySystemComponent : : InitAbilityActorInfo ( AActor * InOwnerActor , AActor * InAvatarActor )
{
FGameplayAbilityActorInfo * ActorInfo = AbilityActorInfo . Get ( ) ;
check ( ActorInfo ) ;
check ( InOwnerActor ) ;
const bool bHasNewPawnAvatar = Cast < APawn > ( InAvatarActor ) & & ( InAvatarActor ! = ActorInfo - > AvatarActor ) ;
Super : : InitAbilityActorInfo ( InOwnerActor , InAvatarActor ) ;
if ( bHasNewPawnAvatar )
{
// Notify all abilities that a new pawn avatar has been set
for ( const FGameplayAbilitySpec & AbilitySpec : ActivatableAbilities . Items )
{
ULyraGameplayAbility * LyraAbilityCDO = CastChecked < ULyraGameplayAbility > ( AbilitySpec . Ability ) ;
if ( LyraAbilityCDO - > GetInstancingPolicy ( ) ! = EGameplayAbilityInstancingPolicy : : NonInstanced )
{
TArray < UGameplayAbility * > Instances = AbilitySpec . GetAbilityInstances ( ) ;
for ( UGameplayAbility * AbilityInstance : Instances )
{
ULyraGameplayAbility * LyraAbilityInstance = CastChecked < ULyraGameplayAbility > ( AbilityInstance ) ;
LyraAbilityInstance - > OnPawnAvatarSet ( ) ;
}
}
else
{
LyraAbilityCDO - > OnPawnAvatarSet ( ) ;
}
}
// Register with the global system once we actually have a pawn avatar. We wait until this time since some globally-applied effects may require an avatar.
if ( ULyraGlobalAbilitySystem * GlobalAbilitySystem = UWorld : : GetSubsystem < ULyraGlobalAbilitySystem > ( GetWorld ( ) ) )
{
GlobalAbilitySystem - > RegisterASC ( this ) ;
}
if ( ULyraAnimInstance * LyraAnimInst = Cast < ULyraAnimInstance > ( ActorInfo - > GetAnimInstance ( ) ) )
{
LyraAnimInst - > InitializeWithAbilitySystem ( this ) ;
}
TryActivateAbilitiesOnSpawn ( ) ;
}
}
void ULyraAbilitySystemComponent : : TryActivateAbilitiesOnSpawn ( )
{
ABILITYLIST_SCOPE_LOCK ( ) ;
for ( const FGameplayAbilitySpec & AbilitySpec : ActivatableAbilities . Items )
{
const ULyraGameplayAbility * LyraAbilityCDO = CastChecked < ULyraGameplayAbility > ( AbilitySpec . Ability ) ;
LyraAbilityCDO - > TryActivateAbilityOnSpawn ( AbilityActorInfo . Get ( ) , AbilitySpec ) ;
}
}
void ULyraAbilitySystemComponent : : CancelAbilitiesByFunc ( TShouldCancelAbilityFunc ShouldCancelFunc , bool bReplicateCancelAbility )
{
ABILITYLIST_SCOPE_LOCK ( ) ;
for ( const FGameplayAbilitySpec & AbilitySpec : ActivatableAbilities . Items )
{
if ( ! AbilitySpec . IsActive ( ) )
{
continue ;
}
ULyraGameplayAbility * LyraAbilityCDO = CastChecked < ULyraGameplayAbility > ( AbilitySpec . Ability ) ;
if ( LyraAbilityCDO - > GetInstancingPolicy ( ) ! = EGameplayAbilityInstancingPolicy : : NonInstanced )
{
// Cancel all the spawned instances, not the CDO.
TArray < UGameplayAbility * > Instances = AbilitySpec . GetAbilityInstances ( ) ;
for ( UGameplayAbility * AbilityInstance : Instances )
{
ULyraGameplayAbility * LyraAbilityInstance = CastChecked < ULyraGameplayAbility > ( AbilityInstance ) ;
if ( ShouldCancelFunc ( LyraAbilityInstance , AbilitySpec . Handle ) )
{
if ( LyraAbilityInstance - > CanBeCanceled ( ) )
{
LyraAbilityInstance - > CancelAbility ( AbilitySpec . Handle , AbilityActorInfo . Get ( ) , LyraAbilityInstance - > GetCurrentActivationInfo ( ) , bReplicateCancelAbility ) ;
}
else
{
UE_LOG ( LogLyraAbilitySystem , Error , TEXT ( " CancelAbilitiesByFunc: Can't cancel ability [%s] because CanBeCanceled is false. " ) , * LyraAbilityInstance - > GetName ( ) ) ;
}
}
}
}
else
{
// Cancel the non-instanced ability CDO.
if ( ShouldCancelFunc ( LyraAbilityCDO , AbilitySpec . Handle ) )
{
// Non-instanced abilities can always be canceled.
check ( LyraAbilityCDO - > CanBeCanceled ( ) ) ;
LyraAbilityCDO - > CancelAbility ( AbilitySpec . Handle , AbilityActorInfo . Get ( ) , FGameplayAbilityActivationInfo ( ) , bReplicateCancelAbility ) ;
}
}
}
}
void ULyraAbilitySystemComponent : : CancelInputActivatedAbilities ( bool bReplicateCancelAbility )
{
2022-09-13 07:18:28 +00:00
auto ShouldCancelFunc = [ this ] ( const ULyraGameplayAbility * LyraAbility , FGameplayAbilitySpecHandle Handle )
2022-05-23 18:41:30 +00:00
{
const ELyraAbilityActivationPolicy ActivationPolicy = LyraAbility - > GetActivationPolicy ( ) ;
return ( ( ActivationPolicy = = ELyraAbilityActivationPolicy : : OnInputTriggered ) | | ( ActivationPolicy = = ELyraAbilityActivationPolicy : : WhileInputActive ) ) ;
} ;
CancelAbilitiesByFunc ( ShouldCancelFunc , bReplicateCancelAbility ) ;
}
void ULyraAbilitySystemComponent : : AbilitySpecInputPressed ( FGameplayAbilitySpec & Spec )
{
Super : : AbilitySpecInputPressed ( Spec ) ;
// We don't support UGameplayAbility::bReplicateInputDirectly.
// Use replicated events instead so that the WaitInputPress ability task works.
if ( Spec . IsActive ( ) )
{
// Invoke the InputPressed event. This is not replicated here. If someone is listening, they may replicate the InputPressed event to the server.
InvokeReplicatedEvent ( EAbilityGenericReplicatedEvent : : InputPressed , Spec . Handle , Spec . ActivationInfo . GetActivationPredictionKey ( ) ) ;
}
}
void ULyraAbilitySystemComponent : : AbilitySpecInputReleased ( FGameplayAbilitySpec & Spec )
{
Super : : AbilitySpecInputReleased ( Spec ) ;
// We don't support UGameplayAbility::bReplicateInputDirectly.
// Use replicated events instead so that the WaitInputRelease ability task works.
if ( Spec . IsActive ( ) )
{
// Invoke the InputReleased event. This is not replicated here. If someone is listening, they may replicate the InputReleased event to the server.
InvokeReplicatedEvent ( EAbilityGenericReplicatedEvent : : InputReleased , Spec . Handle , Spec . ActivationInfo . GetActivationPredictionKey ( ) ) ;
}
}
void ULyraAbilitySystemComponent : : AbilityInputTagPressed ( const FGameplayTag & InputTag )
{
if ( InputTag . IsValid ( ) )
{
for ( const FGameplayAbilitySpec & AbilitySpec : ActivatableAbilities . Items )
{
if ( AbilitySpec . Ability & & ( AbilitySpec . DynamicAbilityTags . HasTagExact ( InputTag ) ) )
{
InputPressedSpecHandles . AddUnique ( AbilitySpec . Handle ) ;
InputHeldSpecHandles . AddUnique ( AbilitySpec . Handle ) ;
}
}
}
}
void ULyraAbilitySystemComponent : : AbilityInputTagReleased ( const FGameplayTag & InputTag )
{
if ( InputTag . IsValid ( ) )
{
for ( const FGameplayAbilitySpec & AbilitySpec : ActivatableAbilities . Items )
{
if ( AbilitySpec . Ability & & ( AbilitySpec . DynamicAbilityTags . HasTagExact ( InputTag ) ) )
{
InputReleasedSpecHandles . AddUnique ( AbilitySpec . Handle ) ;
InputHeldSpecHandles . Remove ( AbilitySpec . Handle ) ;
}
}
}
}
void ULyraAbilitySystemComponent : : ProcessAbilityInput ( float DeltaTime , bool bGamePaused )
{
if ( HasMatchingGameplayTag ( TAG_Gameplay_AbilityInputBlocked ) )
{
ClearAbilityInput ( ) ;
return ;
}
static TArray < FGameplayAbilitySpecHandle > AbilitiesToActivate ;
AbilitiesToActivate . Reset ( ) ;
//@TODO: See if we can use FScopedServerAbilityRPCBatcher ScopedRPCBatcher in some of these loops
//
// Process all abilities that activate when the input is held.
//
for ( const FGameplayAbilitySpecHandle & SpecHandle : InputHeldSpecHandles )
{
if ( const FGameplayAbilitySpec * AbilitySpec = FindAbilitySpecFromHandle ( SpecHandle ) )
{
if ( AbilitySpec - > Ability & & ! AbilitySpec - > IsActive ( ) )
{
const ULyraGameplayAbility * LyraAbilityCDO = CastChecked < ULyraGameplayAbility > ( AbilitySpec - > Ability ) ;
if ( LyraAbilityCDO - > GetActivationPolicy ( ) = = ELyraAbilityActivationPolicy : : WhileInputActive )
{
AbilitiesToActivate . AddUnique ( AbilitySpec - > Handle ) ;
}
}
}
}
//
// Process all abilities that had their input pressed this frame.
//
for ( const FGameplayAbilitySpecHandle & SpecHandle : InputPressedSpecHandles )
{
if ( FGameplayAbilitySpec * AbilitySpec = FindAbilitySpecFromHandle ( SpecHandle ) )
{
if ( AbilitySpec - > Ability )
{
AbilitySpec - > InputPressed = true ;
if ( AbilitySpec - > IsActive ( ) )
{
// Ability is active so pass along the input event.
AbilitySpecInputPressed ( * AbilitySpec ) ;
}
else
{
const ULyraGameplayAbility * LyraAbilityCDO = CastChecked < ULyraGameplayAbility > ( AbilitySpec - > Ability ) ;
if ( LyraAbilityCDO - > GetActivationPolicy ( ) = = ELyraAbilityActivationPolicy : : OnInputTriggered )
{
AbilitiesToActivate . AddUnique ( AbilitySpec - > Handle ) ;
}
}
}
}
}
//
// Try to activate all the abilities that are from presses and holds.
// We do it all at once so that held inputs don't activate the ability
// and then also send a input event to the ability because of the press.
//
for ( const FGameplayAbilitySpecHandle & AbilitySpecHandle : AbilitiesToActivate )
{
TryActivateAbility ( AbilitySpecHandle ) ;
}
//
// Process all abilities that had their input released this frame.
//
for ( const FGameplayAbilitySpecHandle & SpecHandle : InputReleasedSpecHandles )
{
if ( FGameplayAbilitySpec * AbilitySpec = FindAbilitySpecFromHandle ( SpecHandle ) )
{
if ( AbilitySpec - > Ability )
{
AbilitySpec - > InputPressed = false ;
if ( AbilitySpec - > IsActive ( ) )
{
// Ability is active so pass along the input event.
AbilitySpecInputReleased ( * AbilitySpec ) ;
}
}
}
}
//
// Clear the cached ability handles.
//
InputPressedSpecHandles . Reset ( ) ;
InputReleasedSpecHandles . Reset ( ) ;
}
void ULyraAbilitySystemComponent : : ClearAbilityInput ( )
{
InputPressedSpecHandles . Reset ( ) ;
InputReleasedSpecHandles . Reset ( ) ;
InputHeldSpecHandles . Reset ( ) ;
}
void ULyraAbilitySystemComponent : : NotifyAbilityActivated ( const FGameplayAbilitySpecHandle Handle , UGameplayAbility * Ability )
{
Super : : NotifyAbilityActivated ( Handle , Ability ) ;
ULyraGameplayAbility * LyraAbility = CastChecked < ULyraGameplayAbility > ( Ability ) ;
AddAbilityToActivationGroup ( LyraAbility - > GetActivationGroup ( ) , LyraAbility ) ;
}
void ULyraAbilitySystemComponent : : NotifyAbilityFailed ( const FGameplayAbilitySpecHandle Handle , UGameplayAbility * Ability , const FGameplayTagContainer & FailureReason )
{
Super : : NotifyAbilityFailed ( Handle , Ability , FailureReason ) ;
if ( APawn * Avatar = Cast < APawn > ( GetAvatarActor ( ) ) )
{
if ( ! Avatar - > IsLocallyControlled ( ) & & Ability - > IsSupportedForNetworking ( ) )
{
ClientNotifyAbilityFailed ( Ability , FailureReason ) ;
return ;
}
}
HandleAbilityFailed ( Ability , FailureReason ) ;
}
void ULyraAbilitySystemComponent : : NotifyAbilityEnded ( FGameplayAbilitySpecHandle Handle , UGameplayAbility * Ability , bool bWasCancelled )
{
Super : : NotifyAbilityEnded ( Handle , Ability , bWasCancelled ) ;
ULyraGameplayAbility * LyraAbility = CastChecked < ULyraGameplayAbility > ( Ability ) ;
RemoveAbilityFromActivationGroup ( LyraAbility - > GetActivationGroup ( ) , LyraAbility ) ;
}
void ULyraAbilitySystemComponent : : ApplyAbilityBlockAndCancelTags ( const FGameplayTagContainer & AbilityTags , UGameplayAbility * RequestingAbility , bool bEnableBlockTags , const FGameplayTagContainer & BlockTags , bool bExecuteCancelTags , const FGameplayTagContainer & CancelTags )
{
FGameplayTagContainer ModifiedBlockTags = BlockTags ;
FGameplayTagContainer ModifiedCancelTags = CancelTags ;
if ( TagRelationshipMapping )
{
// Use the mapping to expand the ability tags into block and cancel tag
TagRelationshipMapping - > GetAbilityTagsToBlockAndCancel ( AbilityTags , & ModifiedBlockTags , & ModifiedCancelTags ) ;
}
Super : : ApplyAbilityBlockAndCancelTags ( AbilityTags , RequestingAbility , bEnableBlockTags , ModifiedBlockTags , bExecuteCancelTags , ModifiedCancelTags ) ;
//@TODO: Apply any special logic like blocking input or movement
}
void ULyraAbilitySystemComponent : : HandleChangeAbilityCanBeCanceled ( const FGameplayTagContainer & AbilityTags , UGameplayAbility * RequestingAbility , bool bCanBeCanceled )
{
Super : : HandleChangeAbilityCanBeCanceled ( AbilityTags , RequestingAbility , bCanBeCanceled ) ;
//@TODO: Apply any special logic like blocking input or movement
}
void ULyraAbilitySystemComponent : : GetAdditionalActivationTagRequirements ( const FGameplayTagContainer & AbilityTags , FGameplayTagContainer & OutActivationRequired , FGameplayTagContainer & OutActivationBlocked ) const
{
if ( TagRelationshipMapping )
{
TagRelationshipMapping - > GetRequiredAndBlockedActivationTags ( AbilityTags , & OutActivationRequired , & OutActivationBlocked ) ;
}
}
void ULyraAbilitySystemComponent : : SetTagRelationshipMapping ( ULyraAbilityTagRelationshipMapping * NewMapping )
{
TagRelationshipMapping = NewMapping ;
}
void ULyraAbilitySystemComponent : : ClientNotifyAbilityFailed_Implementation ( const UGameplayAbility * Ability , const FGameplayTagContainer & FailureReason )
{
HandleAbilityFailed ( Ability , FailureReason ) ;
}
void ULyraAbilitySystemComponent : : HandleAbilityFailed ( const UGameplayAbility * Ability , const FGameplayTagContainer & FailureReason )
{
//UE_LOG(LogLyraAbilitySystem, Warning, TEXT("Ability %s failed to activate (tags: %s)"), *GetPathNameSafe(Ability), *FailureReason.ToString());
if ( const ULyraGameplayAbility * LyraAbility = Cast < const ULyraGameplayAbility > ( Ability ) )
{
LyraAbility - > OnAbilityFailedToActivate ( FailureReason ) ;
}
}
bool ULyraAbilitySystemComponent : : IsActivationGroupBlocked ( ELyraAbilityActivationGroup Group ) const
{
bool bBlocked = false ;
switch ( Group )
{
case ELyraAbilityActivationGroup : : Independent :
// Independent abilities are never blocked.
bBlocked = false ;
break ;
case ELyraAbilityActivationGroup : : Exclusive_Replaceable :
case ELyraAbilityActivationGroup : : Exclusive_Blocking :
// Exclusive abilities can activate if nothing is blocking.
bBlocked = ( ActivationGroupCounts [ ( uint8 ) ELyraAbilityActivationGroup : : Exclusive_Blocking ] > 0 ) ;
break ;
default :
checkf ( false , TEXT ( " IsActivationGroupBlocked: Invalid ActivationGroup [%d] \n " ) , ( uint8 ) Group ) ;
break ;
}
return bBlocked ;
}
void ULyraAbilitySystemComponent : : AddAbilityToActivationGroup ( ELyraAbilityActivationGroup Group , ULyraGameplayAbility * LyraAbility )
{
check ( LyraAbility ) ;
check ( ActivationGroupCounts [ ( uint8 ) Group ] < INT32_MAX ) ;
ActivationGroupCounts [ ( uint8 ) Group ] + + ;
const bool bReplicateCancelAbility = false ;
switch ( Group )
{
case ELyraAbilityActivationGroup : : Independent :
// Independent abilities do not cancel any other abilities.
break ;
case ELyraAbilityActivationGroup : : Exclusive_Replaceable :
case ELyraAbilityActivationGroup : : Exclusive_Blocking :
CancelActivationGroupAbilities ( ELyraAbilityActivationGroup : : Exclusive_Replaceable , LyraAbility , bReplicateCancelAbility ) ;
break ;
default :
checkf ( false , TEXT ( " AddAbilityToActivationGroup: Invalid ActivationGroup [%d] \n " ) , ( uint8 ) Group ) ;
break ;
}
const int32 ExclusiveCount = ActivationGroupCounts [ ( uint8 ) ELyraAbilityActivationGroup : : Exclusive_Replaceable ] + ActivationGroupCounts [ ( uint8 ) ELyraAbilityActivationGroup : : Exclusive_Blocking ] ;
if ( ! ensure ( ExclusiveCount < = 1 ) )
{
UE_LOG ( LogLyraAbilitySystem , Error , TEXT ( " AddAbilityToActivationGroup: Multiple exclusive abilities are running. " ) ) ;
}
}
void ULyraAbilitySystemComponent : : RemoveAbilityFromActivationGroup ( ELyraAbilityActivationGroup Group , ULyraGameplayAbility * LyraAbility )
{
check ( LyraAbility ) ;
check ( ActivationGroupCounts [ ( uint8 ) Group ] > 0 ) ;
ActivationGroupCounts [ ( uint8 ) Group ] - - ;
}
void ULyraAbilitySystemComponent : : CancelActivationGroupAbilities ( ELyraAbilityActivationGroup Group , ULyraGameplayAbility * IgnoreLyraAbility , bool bReplicateCancelAbility )
{
2022-09-13 07:18:28 +00:00
auto ShouldCancelFunc = [ this , Group , IgnoreLyraAbility ] ( const ULyraGameplayAbility * LyraAbility , FGameplayAbilitySpecHandle Handle )
2022-05-23 18:41:30 +00:00
{
return ( ( LyraAbility - > GetActivationGroup ( ) = = Group ) & & ( LyraAbility ! = IgnoreLyraAbility ) ) ;
} ;
CancelAbilitiesByFunc ( ShouldCancelFunc , bReplicateCancelAbility ) ;
}
void ULyraAbilitySystemComponent : : AddDynamicTagGameplayEffect ( const FGameplayTag & Tag )
{
const TSubclassOf < UGameplayEffect > DynamicTagGE = ULyraAssetManager : : GetSubclass ( ULyraGameData : : Get ( ) . DynamicTagGameplayEffect ) ;
if ( ! DynamicTagGE )
{
UE_LOG ( LogLyraAbilitySystem , Warning , TEXT ( " AddDynamicTagGameplayEffect: Unable to find DynamicTagGameplayEffect [%s]. " ) , * ULyraGameData : : Get ( ) . DynamicTagGameplayEffect . GetAssetName ( ) ) ;
return ;
}
const FGameplayEffectSpecHandle SpecHandle = MakeOutgoingSpec ( DynamicTagGE , 1.0f , MakeEffectContext ( ) ) ;
FGameplayEffectSpec * Spec = SpecHandle . Data . Get ( ) ;
if ( ! Spec )
{
UE_LOG ( LogLyraAbilitySystem , Warning , TEXT ( " AddDynamicTagGameplayEffect: Unable to make outgoing spec for [%s]. " ) , * GetNameSafe ( DynamicTagGE ) ) ;
return ;
}
Spec - > DynamicGrantedTags . AddTag ( Tag ) ;
ApplyGameplayEffectSpecToSelf ( * Spec ) ;
}
void ULyraAbilitySystemComponent : : RemoveDynamicTagGameplayEffect ( const FGameplayTag & Tag )
{
const TSubclassOf < UGameplayEffect > DynamicTagGE = ULyraAssetManager : : GetSubclass ( ULyraGameData : : Get ( ) . DynamicTagGameplayEffect ) ;
if ( ! DynamicTagGE )
{
UE_LOG ( LogLyraAbilitySystem , Warning , TEXT ( " RemoveDynamicTagGameplayEffect: Unable to find gameplay effect [%s]. " ) , * ULyraGameData : : Get ( ) . DynamicTagGameplayEffect . GetAssetName ( ) ) ;
return ;
}
FGameplayEffectQuery Query = FGameplayEffectQuery : : MakeQuery_MatchAnyOwningTags ( FGameplayTagContainer ( Tag ) ) ;
Query . EffectDefinition = DynamicTagGE ;
RemoveActiveEffects ( Query ) ;
}
void ULyraAbilitySystemComponent : : GetAbilityTargetData ( const FGameplayAbilitySpecHandle AbilityHandle , FGameplayAbilityActivationInfo ActivationInfo , FGameplayAbilityTargetDataHandle & OutTargetDataHandle )
{
TSharedPtr < FAbilityReplicatedDataCache > ReplicatedData = AbilityTargetDataMap . Find ( FGameplayAbilitySpecHandleAndPredictionKey ( AbilityHandle , ActivationInfo . GetActivationPredictionKey ( ) ) ) ;
if ( ReplicatedData . IsValid ( ) )
{
OutTargetDataHandle = ReplicatedData - > TargetData ;
}
}