How-To: Add Your Own Augment Event

Augment events are not a fixed list in C++. Any gameplay tag under Augment.Event is an event. Declare the tag, broadcast it when your game knows the thing happened, and it appears in the augment editor's event picker with no registration step and no plugin change.

Why the plugin ships so few events
CrimsonAbilitySystem broadcasts only OnGranted, OnRemoved, OnActivate, OnEnd and OnEffectApplying - the moments it genuinely controls. It does not ship OnCrit or OnKill, because it has no idea what a crit is in your game and could never fire them. A tag that looks authorable but never runs is worse than no tag: the augment reads as correctly configured and silently does nothing.

The two effect-application events

Applying a gameplay effect to targets is two distinct moments, and the plugin broadcasts both. Knowing which one you want is most of the work.

OnEffectApplyingOnEffectResolved
WhenBefore applicationAfter application, per target
Outcome known?No - the execution has not runYes - crit, blocked, immune, damage type
EventMagnitudeThe spec's base valueThe resolved value, post-mitigation
ContextTagsSpec asset tags + ability family tagsThe execution's outcome tags
SpecHandleToModifyValid - change the spec hereUnset; the effect has already landed
Runs onServer, or a predicting clientServer only
"On hit, but only on a crit" needs no new event
Bind a group to OnEffectResolved and set the gate's Required Context Tags to Damage.Result.Crit. The actions then run only on crits. The same works for Damage.Result.Blocked, a damage type, or any combination - those tags are already in the outcome, so no C++ is involved.
Why not just one event
These were a single event called OnHit until recently. That was wrong twice: the plugin has no concept of a "hit" - it applies effects, and whether an effect is damage is the effect's business - and the one broadcast happened before application, so it could never report an outcome. Splitting them means each carries data that is actually true at the moment it fires.

Step 1 - declare the tag

Anywhere under Augment.Event. Nesting is allowed, so Augment.Event.Combat.OnParry works if you would rather group them than keep them flat.

Project Settings > Project > GameplayTags > Manage Gameplay Tags, then Add New Gameplay Tag. Name it Augment.Event.OnCrit and put a comment in the Dev Comment field - that comment becomes the tooltip in the augment editor's event picker, so write when it fires.

Step 2 - broadcast it

Call BroadcastAugmentEvent on the UCrimsonGameplayAbility that caused the thing. The payload carries whatever an augment reacting to the event will need: the targets, a magnitude, and context tags an action gate can test.

Broadcast on the server only
Augment actions apply gameplay effects and spawn actors. Broadcasting on both server and client runs them twice. Every broadcast site below is already inside authority-gated code - keep yours that way.

A working example: OnCrit

CrimsonCore ships this, and it is a good template because it shows the reasoning about where a broadcast belongs. A crit is decided by UCrimsonDamageExecution, which cannot broadcast - it is a calculation, not an ability. What it can do is stamp the outcome onto the effect context. The attribute set then sees that stamp while the damage is applied, on the server, with the instigating ability reachable.

CrimsonDamageExecution.cpp - the execution records the outcome:

cpp
// Stamped onto the shared context, which travels with the effect.
if (bCrit) { Ctx->PopTag.AddTag(CrimsonGameplayTags::Damage_Result_Crit); }

CrimsonHealthSet.cpp - the attribute set broadcasts it:

cpp
// Inside PostGameplayEffectExecute, damage branch, already authority-gated.
if (Ctx && Ctx->PopTag.HasTagExact(CrimsonGameplayTags::Damage_Result_Crit))
{
const UGameplayAbility* SourceAbility = Ctx->GetAbilityInstance_NotReplicated();
if (UCrimsonGameplayAbility* CrimsonAbility =
Cast<UCrimsonGameplayAbility>(const_cast<UGameplayAbility*>(SourceAbility)))
{
FCrimsonAugmentEventPayload Payload;
Payload.EventMagnitude = IncomingDamage;
Payload.ContextTags = Ctx->PopTag; // gates can test Damage.Type.Fire, etc.
// The victim, so an augment can target whoever was hit.
if (AActor* HitActor = OwnerASC->GetAvatarActor_Direct())
{
FGameplayAbilityTargetData_ActorArray* Data = new FGameplayAbilityTargetData_ActorArray();
Data->TargetActorArray.Add(HitActor);
Payload.TargetData.Add(Data);
}
CrimsonAbility->BroadcastAugmentEvent(
FGameplayTagContainer(CrimsonGameplayTags::Augment_Event_OnCrit), Payload);
}
}
Why the ability comes from the context
GetAbilityInstance_NotReplicated() is populated by MakeOutgoingGameplayEffectSpec, so it is set whenever the spec was built through an ability. It is not replicated, which is fine here - this code runs on the server. If your broadcast site already has the ability in hand, use that instead.

Step 3 - use it

Open any augment, press + on the EVENTS section, and your tag is in the list under Augment events, labeled from the tag leaf (OnCrit shows as "On Crit") with your Dev Comment as its tooltip. Add actions to the group and they run whenever you broadcast.

Test it without playing
The Crimson Ability Dev Tools window has a Quick Fire row that lists every Augment.Event tag in the project, including yours. Select an ability in PIE and click the button to fire the event by hand.

What the payload carries

FieldWhat to put in it
TargetDataWho the event happened to. Non-empty means actions run once per target - a 3-target hit executes an action three times, each with one target.
EventMagnitudeA number the event is about - the damage dealt, the stacks consumed. Actions can scale off it.
ContextTagsTags describing this occurrence. Action gates test these, so an augment can react to a fire crit specifically.
OptionalObjectAnything else an action needs. Untyped, so cast on the receiving side.

Events that only reach listeners

The plugin does not ship defensive events. Deciding when a dodge or a block has happened is your game's job, so Augment.Event.OnOwnerDodge, OnOwnerBlock and OnOwnerDamageTaken are yours to declare and to fire with UCrimsonAbilitySystemComponent::BroadcastDefensiveAugmentEvents, which takes any tag. Use those three names and the editor still recognizes them: they describe something happening to the owner rather than something an ability did, so they reach stateful listeners only, and are hidden from the event picker and rejected by validation rather than being authored into a group that would silently never run.

See also

  • Concept: Augment System - event groups, gates and actions
  • How-To: Write a Stateful Augment - for events that need to accumulate across occurrences
  • How-To: Write Augment Tooltips - describing what your event does to the player