Most abilities in the Gameplay Ability System ( GAS ) work the same way: you grant them once when the character spawns, and after that you activate them many times, through input or gameplay events. Your dodge, your attacks, your block, all of them work like this.
But some abilities do not fit this pattern. More than abilities, they are commands: a scripted knockdown, the victim side of a finisher, a “do this exact thing right now” order coming from the server. These abilities should run exactly once and then disappear.
I owned the execution system on Lords of the Fallen, and the victim’s side of an execution is exactly this kind of ability: the target receives a “get executed” order, plays it, and should never carry that ability again.
The manual way, and where it goes wrong
You can do one-shot abilities by hand with three calls:
- GiveAbility to grant it
- TryActivateAbility to run it
- ClearAbility to remove it when it ends
The problem is always step 3, someone forgets it. You need to clear the spec when the ability ends, if not it will stay there forever. After a while your ASC is carrying tons of one-shot specs that will never activate again, and every system that goes through GetActivatableAbilities() has to filter that clutter.
Fortunately, the stock ASC has a function for exactly this case:
// GameplayAbilities/Public/AbilitySystemComponent.h
FGameplayAbilitySpecHandle GiveAbilityAndActivateOnce(
FGameplayAbilitySpec& AbilitySpec,
const FGameplayEventData* GameplayEventData = nullptr);
What it actually does
The function does three things:
- It grants the spec.
- It tries to activate it immediately.
- It removes the grant afterwards, no matter what.
If the activation fails, the spec is cleared on the spot and you get an invalid handle back, so checking the handle tells you if it ran. If the activation succeeds, the spec is marked to be removed when the ability ends, and this works even for latent abilities: the ability can play a montage, wait on ability tasks, take two full seconds, and the grant will still clean itself up the moment EndAbility runs.
There are three things to take into account before using it:
- Authority only. Granting abilities is always a server operation, and this function will simply not run without authority.
- Instanced abilities only, and not Local Only. This is fine, a one-shot ability that plays montages and waits on tasks would be instanced anyway.
- Don’t keep the handle around. The spec removes itself, so the handle is only useful to check the immediate result. If some other code looks it up later, the spec will already be gone.
So my rule is: the moment an ability is really a single command instead of a normal ability, I use GiveAbilityAndActivateOnce instead of the three manual calls. This way you can not forget the cleanup, and the ability list stays clean.
A knockdown bolt, end to end
Here is the pattern in a projectile that knocks down whatever it hits:
void AKnockdownBolt::OnProjectileHit(AActor* HitActor, const FHitResult& Hit)
{
if (!HasAuthority())
{
return;
}
UAbilitySystemComponent* TargetASC =
UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(HitActor);
if (!TargetASC)
{
return;
}
// The event data is your payload: who shot, where it hit, how hard.
FGameplayEventData EventData;
EventData.Instigator = GetInstigator();
EventData.Target = HitActor;
EventData.EventMagnitude = KnockdownForce;
EventData.ContextHandle = TargetASC->MakeEffectContext();
EventData.ContextHandle.AddHitResult(Hit);
FGameplayAbilitySpec Spec(UGA_GetKnockedDown::StaticClass(), /*Level=*/1, INDEX_NONE, this);
TargetASC->GiveAbilityAndActivateOnce(Spec, &EventData);
}
Pay attention to that second parameter, it is really useful. The FGameplayEventData travels into the ability as TriggerEventData, so the knockdown can read the impact and react to it:
void UGA_GetKnockedDown::ActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
const FGameplayEventData* TriggerEventData)
{
const FHitResult* Hit = TriggerEventData
? TriggerEventData->ContextHandle.GetHitResult()
: nullptr;
// Commit, pick the directional knockdown montage from the hit direction,
// play it with Play Montage and Wait, push the character back,
// and call EndAbility when the montage finishes.
}
This is much better than hardcoding the reaction in the projectile, because the ability runs on the target, with the target’s ASC, tags and attributes. For instance, a boss with a StatusImmuneKnockdown tag in the ability’s Activation Blocked Tags will simply fail the activation ( and remember, a failed activation cleans the spec too ). As you can see, the bolt does not need to know any of this, it just fires the command and the ability either activates or it does not.
One networking thing to take into account: the activation happens on the server. For AI targets, Server Only execution is enough, because the montage plays through the ASC and replicates by default. For player targets you want Server Initiated, so the owning client runs the ability too.
Other places where this is useful in combat
There are tons of other places in combat where this same pattern helps:
- Executions and finishers. The attacker runs their normal finisher ability, and the victim receives GiveAbilityAndActivateOnce with the “get executed” ability that plays the synced montage.
- Traps. A bear trap does not need every character in the game to carry
GA_TrappedByBearTrap, the trap simply gives it to you on overlap. - Boss phase transitions. The scripted “roar and jump to the center of the arena” runs once, exactly when the AI decides, and never appears in the boss ability list again.
- Scripted and cutscene moments. Same thing can be done from level scripting, you can make any character perform any ability without touching how that character was set up.
When NOT to use it
If the behavior should exist for a duration instead of a single moment, this is the wrong tool. Ex: “While burning, you have a Panic ability”. That is not a command, it is a temporary ability. In that case you grant it through a Gameplay Effect ( the Grant Abilities component of the effect ) and let the lifetime of the effect add and remove the ability for you. I covered those components in the Gameplay Effect Components post.
So this is the rule I use:
- For a permanent ability, GiveAbility.
- For a temporary ability tied to an effect, grant it through the Gameplay Effect.
- For a single command, GiveAbilityAndActivateOnce.
If you want to find candidates in your own project, search for TryActivateAbility. If some of them come right after a GiveAbility and are followed by a manual ClearAbility ( or worse, not followed by one ) you have found your first candidate.
Recap
- It is server-only and it needs instanced, non-Local-Only abilities. Don’t store the returned handle, the spec it points to removes itself.
- GiveAbilityAndActivateOnce grants a spec, activates it, and removes it by itself, even for latent abilities. The cleanup happens when EndAbility runs, and a failed activation cleans up on the spot and returns an invalid handle.
- In the end the decision is simple: a permanent ability goes through GiveAbility, a temporary ability tied to an effect goes through the Gameplay Effect with Grant Abilities, and a single command goes through GiveAbilityAndActivateOnce.


