Description

When playing Standalone or as Listen Server, whenever a GameplayEffect with a duration is applied that fires gameplay cues, the server will locally execute OnActive twice on GameplayCueNotify_Actors that listen to that cue tag.

This seems to happen when applying the GE to an AbilitySystemComponent with replication mode Mixed or Minimal. UAbilitySystemComponent::ApplyGameplayEffectSpecToSelf executes the cue twice: once via ActiveGameplayEffects.ApplyGameplayEffectSpec() and once via InvokeGameplayCueEvent().

Expected: The GameplayCueNotify_Actor's OnActive function is only executed once on the server per GE application.

Steps to Reproduce

Quick repro steps (attached project)

Download the attached project and compile it with UE 5.2. Start PIE as standalone or listen server. Press T to apply a GE with duration that fires a cue that is handled by a GCN. See that OnActive is executed twice (two printed logs). Expected: only executed once.

Complete repro steps

Make the cue handler

  • Create a blueprint inheriting from GameplayCueNotify_Actor called GCN_TestNotify
  • Open it and set its GameplayCueTag to a tag you'll create now: GameplayCue.Test
  • Override the OnActive function in the blueprint to print Hello

Make the GameplayEffect

  • Create a blueprint inheriting from GameplayEffect called GE_Test
  • Set it's DurationPolicy to Has Duration and assign it a value of 3 (seconds)
  • Under GameplayCues, add an entry so that it triggers a cue with tag GameplayCue.Test

Configure the character and apply the GameplayEffect

  • Have a character class with a native AbilitySystemComponent
  • Set the ASC's replication mode to Minimal or Mixed
  • Modify the blueprint graph: on key press call AbilitySystemComponent->ApplyGameplayEffectToSelf with GE class: GE_Test

Repro the bug:

  • Start play: either PIE or Standalone, running as Standalone or Listen Server
  • Press the key to apply the GE to self
  • Observe that OnActive executes twice (Hello is printed twice){}
    • This happens in Standalone, so isn't a case of once on server+once on client
    • As a Listen Server, the log messages read Server: Hello so the function is executed twice on the server
  • Expected: OnActive executes only
Callstack

Callstack 1 (first occurrence of OnActive):

AGameplayCueNotify_Actor::HandleGameplayCue(AActor *,Type,const FGameplayCueParameters &) GameplayCueNotify_Actor.cpp:190
UGameplayCueSet::HandleGameplayCueNotify_Internal(AActor *,int,Type,FGameplayCueParameters &) GameplayCueSet.cpp:325
UGameplayCueSet::HandleGameplayCue(AActor *,FGameplayTag,Type,const FGameplayCueParameters &) GameplayCueSet.cpp:85
UGameplayCueManager::RouteGameplayCue(AActor *,FGameplayTag,Type,const FGameplayCueParameters &,EGameplayCueExecutionOptions) GameplayCueManager.cpp:216
UGameplayCueManager::HandleGameplayCue(AActor *,FGameplayTag,Type,const FGameplayCueParameters &,EGameplayCueExecutionOptions) GameplayCueManager.cpp:158
UAbilitySystemComponent::InvokeGameplayCueEvent(FGameplayTag,Type,const FGameplayCueParameters &) AbilitySystemComponent.cpp:1267
UAbilitySystemComponent::NetMulticast_InvokeGameplayCueAdded_WithParams_Implementation(FGameplayTag,FPredictionKey,FGameplayCueParameters) AbilitySystemComponent.cpp:1477
UAbilitySystemComponent::execNetMulticast_InvokeGameplayCueAdded_WithParams(UObject *,FFrame &,void *const) 0x00007ff94bb30ec8
UFunction::Invoke(UObject *,FFrame &,void *const) Class.cpp:6411
UObject::ProcessEvent(UFunction *,void *) ScriptCore.cpp:2129
UAbilitySystemComponent::NetMulticast_InvokeGameplayCueAdded_WithParams(FGameplayTag,FPredictionKey,FGameplayCueParameters) 0x00007ff94bb00eab
IAbilitySystemReplicationProxyInterface::Call_InvokeGameplayCueAdded_WithParams(FGameplayTag,FPredictionKey,FGameplayCueParameters) AbilitySystemReplicationProxyInterface.cpp:43
UAbilitySystemComponent::AddGameplayCue_Internal(FGameplayTag,const FGameplayCueParameters &,FActiveGameplayCueContainer &) AbilitySystemComponent.cpp:1348
UAbilitySystemComponent::AddGameplayCue_Internal(FGameplayTag,FGameplayEffectContextHandle &,FActiveGameplayCueContainer &) AbilitySystemComponent.cpp:1307
UAbilitySystemComponent::AddGameplayCue_MinimalReplication(FGameplayTag,FGameplayEffectContextHandle) AbilitySystemComponent.cpp:1295
FActiveGameplayEffectsContainer::AddActiveGameplayEffectGrantedTagsAndModifiers(FActiveGameplayEffect &,bool) GameplayEffect.cpp:3442
FActiveGameplayEffect::CheckOngoingTagRequirements(const FGameplayTagContainer &,FActiveGameplayEffectsContainer &,bool) GameplayEffect.cpp:1771
FActiveGameplayEffectsContainer::InternalOnActiveGameplayEffectAdded(FActiveGameplayEffect &) GameplayEffect.cpp:3321
FActiveGameplayEffectsContainer::ApplyGameplayEffectSpec(const FGameplayEffectSpec &,FPredictionKey &,bool &) GameplayEffect.cpp:3264
UAbilitySystemComponent::ApplyGameplayEffectSpecToSelf(const FGameplayEffectSpec &,FPredictionKey) AbilitySystemComponent.cpp:842
UAbilitySystemComponent::ApplyGameplayEffectToSelf(const UGameplayEffect *,float,const FGameplayEffectContextHandle &,FPredictionKey) AbilitySystemComponent.cpp:536
UAbilitySystemComponent::BP_ApplyGameplayEffectToSelf(TSubclassOf<UGameplayEffect>,float,FGameplayEffectContextHandle) AbilitySystemComponent.cpp:518

Callstack 2 (second occurrence of OnActive):

AGameplayCueNotify_Actor::HandleGameplayCue(AActor *,Type,const FGameplayCueParameters &) GameplayCueNotify_Actor.cpp:190
UGameplayCueSet::HandleGameplayCueNotify_Internal(AActor *,int,Type,FGameplayCueParameters &) GameplayCueSet.cpp:325
UGameplayCueSet::HandleGameplayCue(AActor *,FGameplayTag,Type,const FGameplayCueParameters &) GameplayCueSet.cpp:85
UGameplayCueManager::RouteGameplayCue(AActor *,FGameplayTag,Type,const FGameplayCueParameters &,EGameplayCueExecutionOptions) GameplayCueManager.cpp:216
UGameplayCueManager::HandleGameplayCue(AActor *,FGameplayTag,Type,const FGameplayCueParameters &,EGameplayCueExecutionOptions) GameplayCueManager.cpp:158
UGameplayCueManager::HandleGameplayCues(AActor *,const FGameplayTagContainer &,Type,const FGameplayCueParameters &,EGameplayCueExecutionOptions) GameplayCueManager.cpp:131
UAbilitySystemComponent::InvokeGameplayCueEvent(const FGameplayEffectSpecForRPC &,Type) AbilitySystemComponent.cpp:1247
UAbilitySystemComponent::ApplyGameplayEffectSpecToSelf(const FGameplayEffectSpec &,FPredictionKey) AbilitySystemComponent.cpp:909
UAbilitySystemComponent::ApplyGameplayEffectToSelf(const UGameplayEffect *,float,const FGameplayEffectContextHandle &,FPredictionKey) AbilitySystemComponent.cpp:536
UAbilitySystemComponent::BP_ApplyGameplayEffectToSelf(TSubclassOf<UGameplayEffect>,float,FGameplayEffectContextHandle) AbilitySystemComponent.cpp:518

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-191936 in the post.

4
Login to Vote

Fixed
ComponentUE - Gameplay - Gameplay Ability System
Affects Versions5.2
Target Fix5.4
Fix Commit29940014
Main Commit29940014
CreatedAug 2, 2023
ResolvedNov 28, 2023
UpdatedDec 19, 2023