UE5.5.4 GAS - GAS Block Abilities with Tag Not Working With Parent Tags

I’m setting up tags for a Gameplay Ability and have added a parent tag (e.g., Ability.Weapon) to the ability’s Block Abilities with Tag container.

I think when this ability is active, it should block any other ability that has a matching child tag (e.g., an ability tagged with Ability.Weapon.Sword) from being activated.
But In my testing, it can’t block any Ability(except Tag is exactly matched).

Is my understanding incorrect, or is this a potential bug? I’m working in version 5.5.4.

1 Like

Unfortunately the cancel abilities with tag or block abilities with tag containers does not block all child tags when a parent tag is set in it.

If I am not mistaken.

You should try making your own GA in order to make that logic.
And I also do think that logic would be quite useful if Epic did make this an update in GAS.

So I actually think this is an engine bug introduced in 5.5. Not entirely sure, but here’s what I found:

The function that decides whether an ability is “blocked” (among other things) is DoesAbilitySatisfyTagRequirements()

In UE 5.3 this was the code segement that checked the ability tags against the blocked tags. In GameplayAbility.cpp:

...
	// Check if any of this ability's tags are currently blocked
	if (AbilitySystemComponent.AreAbilityTagsBlocked(AbilityTags))
	{
		bBlocked = true;
	}
...

Which calls this function in AbilitySystemComponent_Abilities.cpp:

bool UAbilitySystemComponent::AreAbilityTagsBlocked(const FGameplayTagContainer& Tags) const
{
	// Expand the passed in tags to get parents, not the blocked tags
	return Tags.HasAny(BlockedAbilityTags.GetExplicitGameplayTags());
}

Pretty simple. Note that it’s asking if the Ability Tags contain the Blocked Tags. This is important.

Now this is the new code in UE5.5:

auto CheckForBlocked = [&](const FGameplayTagContainer& ContainerA, const FGameplayTagContainer& ContainerB)
	{
		// Do we not have any tags in common?  Then we're not blocked
		if (ContainerA.IsEmpty() || ContainerB.IsEmpty() || !ContainerA.HasAny(ContainerB))
		{
			return;
		}

		....

		bBlocked = true;
	};

Which is a lambda function called later in the funciton like so:

CheckForBlocked(AbilitySystemComponent.GetBlockedAbilityTags(), GetAssetTags());

Meaning ContainerA is the Blocked Tags and ContainerB is the AbilityTags (Or AssetTags as they are now called).
Hence this function is asking if the Blocked Tags contain the Ability Tags. Which is backwards!!!

This means parent tags such Ability.Attack won’t block Ability.Attack.Melee when they did previously. Because while Ability.Attack.Melee contains Ability.Attack (UE 5.3), the reverse isn’t true! Ability.Attackdoesn’t contain Ability.Attack.Melee!

The only workaround I can offer is to override DoesAbilitySatisfyTagRequirements() and change this line. Reversing the comparison:

// Do we not have any tags in common?  Then we're not blocked
		if (ContainerA.IsEmpty() || ContainerB.IsEmpty() || !ContainerB.HasAny(ContainerA)) // <-- FIX!!!