Skip to content
Back to wiki

Register the First Attack Result

A

Author

Author

Created: Oct 21, 2026Updated: Oct 21, 2026

Table of contents

Register the First Attack Result

This page builds the smallest settlement loop: an instantiable UGCS_CombatFlow subclass, a project wire from GGA's attribute-execute callback into HandleGameplayEffectExecute, then an FGCS_AttackResult passed to RegisterAttackResult. When it works, the Debugger Attack Result section shows the latest entry and a Default processor runs once. Melee windows and bullet spawning are out of scope.

Related pages: the runtime path is in Combat Flow and Attack Results; processor policy is in Processors and Combat Hooks. GGA attribute callbacks are in the GGA attribute-set docs.

Prerequisites

  1. You attached UGCS_CombatSystemComponent from Attach Combat Components. The authority already called InitializeAbilitySystem, and Globals is UGGA_AbilitySystemGlobals.
  2. The target actor has UGGA_AttributeSystemComponent, and it owns an AttributeSet that forwards PostGameplayEffectExecute through UGGA_AttributeSetEventBridge. GGA's UAS_Health / UAS_Combat and GCS's UAS_Poise all do this. A custom AttributeSet that never forwards will never reach Combat Flow.
  3. Prepare an instant Gameplay Effect that changes an attribute Base Value (for example UAS_Health Health or IncomingDamage). A duration effect that only adds tags never enters PostExecute.
  4. Prepare one FGCS_AttackDefinition row whose TargetEffectClass points at that instant GE.

The plugin does not call HandleGameplayEffectExecute from the attribute callback. The combat component only forwards Globals PreApply to the Flow. PostExecute must be wired by the project.

1. Subclass Combat Flow and add one processor

Create a Blueprint whose parent is UGCS_CombatFlow (display name GCS Combat Flow). The base class is Abstract and cannot be assigned to CombatFlowClass.

In Class Defaults, add one UGCS_AttackResultProcessor_GameplayEvent or UGCS_AttackResultProcessor_GameplayCue to AttackResultProcessors:

  • Set ExecutePolicy to Default.
  • Give the Event processor at least one EventTriggers tag, or give the Cue processor at least one Cue tag (or a non-empty TargetGameplayCues on the attack definition).
  • Do not add UGCS_AttackResultProcessor_Death. Its native implementation is empty and only logs a Warning on first run.

The processor must live on this subclass instance. Editing the CDO while CombatFlowClass points at a different empty subclass still leaves the list empty.

Assign that Blueprint to the target UGCS_CombatSystemComponent.CombatFlowClass. Authority BeginPlay NewObjects the Flow and replicates it to clients.

2. Forward the GGA callback to the Flow

On the target actor, send FGGA_GameplayEffectModCallbackData into the Flow through either entry. Pick one.

Entry

What to do

Blueprint bind

Listen to UGGA_AttributeSystemComponent.OnPostGameplayEffectExecute. Get the Combat Flow and call Handle Gameplay Effect Execute with the same payload.

Project AttributeSystem subclass

Override HandlePostGameplayEffectExecute and call GetCombatFlow()->HandleGameplayEffectExecute(Payload).

Payload.TargetActor is the actor whose attribute changed. Resolve the combat component on that actor. If AttributeSystem is missing, EventBridge drops the forward and the Flow is never called.

An instant GE with UGCS_GEComponent_PredictivelyExecute also enters this bind on a local predicted execute. This page verifies an authoritative instant GE first. Leave prediction off.

3. Register the result in the Flow

Override HandleGameplayEffectExecute on the Flow subclass (same-named Blueprint event). The base implementation is empty: wiring without an override still leaves the container empty.

Minimum fill:

  1. Create an FGCS_AttackResult.
  2. EffectContextHandle ← Payload.ContextHandle.
  3. AggregatedSourceTags / AggregatedTargetTags ← the same containers on the payload.
  4. Leave OptionalObject empty for this page.
  5. Call RegisterAttackResult on the owning UGCS_CombatSystemComponent.

RegisterAttackResult accepts authority results, or local results whose context is predicting. A client result that is neither is rejected with a Warning.

The plugin does not decide whether this execute counts as an attack. Healing, regen, and stamina costs also enter the function if they hit PostExecute. A first pass may register everything. Shipping projects usually read Get Attack Definition Handle from the Context and return when the handle is invalid, so non-combat GEs stay out of the container.

Do not Apply another GE here, and do not reimplement HandleAttackResult. After RegisterAttackResult writes the FastArray, the default implementation dispatches processors by ExecutePolicy.

4. Execute once with attack context

On the authority, Apply the instant GE from step 3 to the target. Before Apply, use UGCS_CombatFunctionLibrary to write the attack-definition handle into the Effect Context (Set Attack Definition Handle or AddAttackHandleToGameplayEffectSpec).

A debug key, a level script, or a test ability that only Applies the GE is enough. You do not need Trace or bullets yet. If a later hit window lands and still produces no Result, come back here before changing channels or animation.

Expected result

After authority PIE, the target Shared section shows a Combat Flow instance and the Combat section lists the processor you added. After one instant GE with an attack handle, the Attack Result section shows the latest entry, and LastProcessedAttackResult reads the same row. The Default processor fires its Event or Cue once.

Verify

  1. Gameplay Debugger Combat category: Shared shows a Combat Flow; Combat shows a non-empty processor list.
  2. After Apply, Attack Result shows the latest entry and the attack-definition handle.
  3. Get Attack Definition Handle on the Effect Context returns the row from this page.
  4. LogGCS_Combat at Verbose shows settlement. A missing Flow logs an Error on register.
  5. In multiplayer PIE, check the server window for the Result. Client presentation does not prove settlement.

Common failures

Symptom

Check first

Combat Flow stays None

CombatFlowClass empty, or set to the abstract base

AttributeSet changed, Flow event never runs

Target has AttributeSystem; AttributeSet forwards through EventBridge; the bind is OnPostGameplayEffectExecute

Flow event runs, container stays empty

HandleGameplayEffectExecute is overridden and calls RegisterAttackResult

Registration rejected

Called on a non-authority machine without a predicting context

GE applied, no PostExecute

The effect is instant and changes a Base Value; duration modifiers never enter this callback

Result exists, no Event / Cue

Processor is on this Flow subclass; bEditorDebugEnabled is on; Event/Cue tags are not empty

Heals or regen also become Attack Results

The project did not filter on the attack-definition handle. That filter is a project rule, not a plugin default

Death Processor added, nobody dies

Native implementation is empty; do not use it to prove this loop

Next

Once the container shows a result, continue with Author a Melee Attack or Author a Ranged Attack. Processor policy and combo hooks stay in Processors and Combat Hooks.