Here is a good way to activate abilities that have been given to the ASC, useful for passive abilities (Abilities that automatically run without triggers/user activation).
First we will need to add a custom bool to your custom Gameplay Ability class.
/** Ability is passive and auto activates */
UPROPERTY(EditDefaultsOnly, Category = Activation)
bool bPassiveAbility = false;
And we need to override one function from the GameplayAbility and our custom function to activate the ability if it is passive
virtual void OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) override;
//Called to try to active the passive ability
void TryActivatePassiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) const;
Now in the cpp file, lets implement the override above
void UKaosGameplayAbility::OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec)
{
Super::OnGiveAbility(ActorInfo, Spec);
TryActivatePassiveAbility(ActorInfo, Spec);
}
And now onto the actual activation logic
void UKaosGameplayAbility::TryActivatePassiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) const
{
const bool bIsPredicting = (Spec.ActivationInfo.ActivationMode == EGameplayAbilityActivationMode::Predicting);
// Try to activate if activation type is Passive. Passive abilities are auto activated when given.
if (ActorInfo && !Spec.IsActive() && !bIsPredicting && bPassiveAbility))
{
UAbilitySystemComponent* ASC = ActorInfo->AbilitySystemComponent.Get();
const AActor* AvatarActor = ActorInfo->AvatarActor.Get();
// If avatar actor is torn off or about to die, don't try to activate it.
if (ASC && AvatarActor && !AvatarActor->GetTearOff() && (AvatarActor->GetLifeSpan() <= 0.0f))
{
const bool bIsLocalExecution = (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::LocalPredicted) || (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::LocalOnly);
const bool bIsServerExecution = (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::ServerOnly) || (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::ServerInitiated);
const bool bClientShouldActivate = ActorInfo->IsLocallyControlled() && bIsLocalExecution;
const bool bServerShouldActivate = ActorInfo->IsNetAuthority() && bIsServerExecution;
if (bClientShouldActivate || bServerShouldActivate)
{
ASC->TryActivateAbility(Spec.Handle);
}
}
}
}
The above code checks the state of the ability, checks if bPassiveAbility is true, then it checks the avatar actor to make sure its sane to activate this ability. Then we do some checks to make sure we are the correct network client or authority to activate the ability. For example we are server for Server Only and Server Initiated, or we are locally controlled for Local Predicted and LocalOnly.
One other thing i also do is override InitAbilityActorInfo in the AbilitySystemComponent
void UKaosCoreAbilitySystemComponent::InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor)
{
Super::InitAbilityActorInfo(InOwnerActor, InAvatarActor);
if (InAvatarActor != nullptr)
{
ABILITYLIST_SCOPE_LOCK();
for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
{
const UKaosCoreGameplayAbility* KaosAbilityCDO = CastChecked<UKaosCoreGameplayAbility>(AbilitySpec.Ability);
if (KaosAbilityCDO&& KaosAbilityCDO->bPassiveAbility)
{
KaosAbilityCDO->TryActivatePassiveAbility(AbilityActorInfo.Get(), AbilitySpec);
}
}
}
}
Hope this helps people. You can always find me on www.unrealslackers.org.