Is there bloody anything in the AbilitySystemComponent (ASC ) that would return true/false if an ability can be activated? Ideally passing an ability class.
There’s a method “TryActivateAbilityByClass” that does exactly that and returns true if successful. I want that without activating the ability. I just want to know if its possible.
ie.:
Does the ASC have the ability?
Is the ability on CD?
Are there any blocking tags?
Is check cost valid?
etc …
I tried reading the .cpp file for AbilitySystemComponent, and tho the method appears in the .h, its nowhere to be found in the .cpp …!?
I want this method to expose it in a Behaviour Tree Task ‘CanAbilityBeUsed’ and then ‘UseAbility’.
I, too, found this hard to track down exactly how the sequence of events worked.
CanActivateAbility() can be found in GameplayAbility.h at line 285 for me. This is not exposed to BP so you will have to do that yourself.
You can see how the TryActivateAbilityByClass() is used in AbilitySystemComponent_Abilities.cpp at line 1309 and remove the portions that try to activate the ability replacing it with the CanActivateAbility() to get a return. It’s used in that implementation at line 1387 in AbilitySystemComponent_Abilities.cpp
Ok, now I got it!
I deleted my previous post to avoid cluttering.
Turns out I dont need to set-up ‘SourceTags’, ‘TargetTags’ nor even ‘OptionalRelevantTags’.
This works respecting tag requirements, cooldowns and costs.
Based on the guidelines you gave me the code looks like this:
// fyi: look class UAbilitySystemComponent_Abilities.cpp : TryActivateAbilityByClass
bool UAbilitySystemComponent_Crow::CanAbilityBeActivated(TSubclassOf<UGameplayAbility> AbilityClass) const
{
// Try find ability by class
const UGameplayAbility* const abilityCDO = AbilityClass.GetDefaultObject();
FGameplayAbilitySpec abilitySpec;
FGameplayAbilitySpecHandle handle;
for (const FGameplayAbilitySpec& iSpec : ActivatableAbilities.Items)
{
if (iSpec.Ability == abilityCDO)
{
abilitySpec = iSpec;
handle = abilitySpec.Handle;
break;
}
}
// If we have an instanced ability, call CanActivateAbility on it.
// Otherwise we always do a non instanced CanActivateAbility check using the CDO of the Ability.
UGameplayAbility* ability = abilitySpec.GetPrimaryInstance();
if (ability == nullptr)
{
ability = abilitySpec.Ability;
if (ability == nullptr)
{
return false;
}
}
if (ability == false)
{
return false;
}
const FGameplayAbilityActorInfo* actorInfo = AbilityActorInfo.Get();
// make sure the ActorInfo and then Actor on that FGameplayAbilityActorInfo are valid, if not bail out.
if (actorInfo == nullptr || !actorInfo->OwnerActor.IsValid() || !actorInfo->AvatarActor.IsValid())
{
return false;
}
return ability->CanActivateAbility(handle, actorInfo, nullptr, nullptr, nullptr);
}