How to use Gameplay Ability With Event OnAbilityRemoved

UE 5.11

While I was learning Lyra, I found an interesting Ability - GA_AbilityWithWidget.

It uses two events Event OnAbilityAdded and Eevent OnAbilityRemoved.

I’ve done my own experiment, granting the ability via the Ability Component hoping it would create a Widget via UIExtension when the ability is granted, and then remove the Widget from the UI when the ability is removed.

But now it has two problems.

First, when OnAbilityAdded, I added an element to WidgetExtensionHandles, but when OnAbilityRemoved, the array is empty.

why is that? I’m confused.

Secondly, I found a strange thing, if I set Activation Policy == On Input Triggered in the Class Defaults of this GA_AbilityWithWidget, my blueprint node (Event OnAbilityRemoved) will not execute, although I see in the Debug that it does executes the C++ code OnRemoveAbility.

void ULyraGameplayAbility::OnRemoveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec)  
{  
	K2_OnAbilityRemoved(); // Execute
	  
	Super::OnRemoveAbility(ActorInfo, Spec).  
}

When I change Activation Policy == On Spawn, the blueprint node executes correctly.

How do I fix the above problem?

Lyra GA_AbilityWithWidget:

I just rewrote the logic in C++ and it works great, no problem. This blueprint is really hard for me, what am I doing wrong?

The Blueprint’s Activation Policy is also On Input Triggered

::OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo,
                                                               const FGameplayAbilitySpec& Spec)
{
	Super::OnGiveAbility(ActorInfo, Spec);

	UUIExtensionSubsystem* UIExtensionSubsystem = GetWorld()->GetSubsystem<UUIExtensionSubsystem>();
	this->WidgetExtensionHandle = UIExtensionSubsystem->RegisterExtensionAsWidgetForContext(
		this->WidgetExtensionPointTag,
		GetOwningActorFromActorInfo(), this->WidgetClass, -1);

	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, TEXT("OnGiveAbility"));
	}
}
::OnRemoveAbility(const FGameplayAbilityActorInfo* ActorInfo,
                                                                 const FGameplayAbilitySpec& Spec)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, TEXT("OnRemoveAbility"));
	}
	UUIExtensionSubsystem* UIExtensionSubsystem = GetWorld()->GetSubsystem<UUIExtensionSubsystem>();
	this->WidgetExtensionHandle.Unregister();
	
	Super::OnRemoveAbility(ActorInfo, Spec);
}

Check the AbilitySystemComponent::OnRemoveAbility, It only trigger the OnRemoveAbility on primaryinstance if there is one.

// Notify the ability that it has been removed.  It follows the same pattern as OnGiveAbility() and is only called on the primary instance of the ability or the CDO.
	UGameplayAbility* PrimaryInstance = Spec.GetPrimaryInstance();
	if (PrimaryInstance)
	{
		PrimaryInstance->OnRemoveAbility(AbilityActorInfo.Get(), Spec);
	}
	else
	{
		Spec.Ability->OnRemoveAbility(AbilityActorInfo.Get(), Spec);
	}
2 Likes