Skip to content
Back to wiki

Processors and combat hooks

A

Author

Author

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

Table of contents

Processors and combat hooks

Decide whether you need to change “what happens after a hit,” “what tags to stamp before a GE applies,” “whether the combo may advance,” or “who to notify after the step changes.” The first three have dedicated seams. Do not start by rewriting bullet replication or the FastArray.

Related pages: first wiring in Register the First Attack Result, fields in Developer settings and combat data, runtime in Combat Flow and attack results.

Decide whether to extend

Need

Is the default enough?

Extension entry

Fire a Gameplay Event / play a Cue on hit

Yes

Built-in GameplayEvent and GameplayCue processors

Poise break, death, combat log

No project rules by default

Subclass UGCS_AttackResultProcessor

Branch settlement on source / target tags

Queries already exist

UGCS_AttackResultProcessor_WithTagRequirement

Append dynamic tags before a GE applies

Empty base implementation

HandlePreGameplayEffectSpecApply

Turn an attribute callback into an AttackResult

Empty base; project must fill it

HandleGameplayEffectExecute

Combo gates, extra selection rules

Default allows every advance

AllowAdvanceCombo / CanSelectedComboDefinition

Drive an anim layer or UI from the step

Component already broadcasts

OnComboStepChanged / OnComboStepChangedEvent

Immediate local melee hit feedback

Component already exists

Add UGCS_GEComponent_PredictivelyExecute on the Instant GE; use LocalPredicted processors

A good custom case: a Default processor reads UAS_Poise, applies a break GE when poise hits 0, and writes a combat-log line. Do not expect the built-in Death processor to do this — its native Handle is empty and the first call logs a Warning.

A case the default already covers: play a hit-react Event on the target and a hit Cue on the attacker. Put GameplayEvent (bSendToAttacker as needed) and GameplayCue processors on Combat Flow. Cue tags can live on the processor, or on the attack definition’s TargetGameplayCues (a non-empty list replaces the processor list).

Subclass a processor

UGCS_AttackResultProcessor is Abstract, EditInlineNew, DefaultToInstanced, and Const. Place it on Combat Flow’s AttackResultProcessors. The entry is HandleIncomingAttackResult. ProcessIncomingAttackResult skips results that are already bConsumed. After adding one, confirm it is instanced on CombatFlowClass, not only on the CDO.

UGCS_AttackResultProcessor_WithTagRequirement filters aggregated tags with SourceTagQuery / TargetTagQuery before calling Handle. An empty query matches. Use it to branch on attack type instead of writing HasTag in every processor.

Built-in

What it does

Is the default enough?

UGCS_AttackResultProcessor_Death

Placeholder. Native Handle is empty; first call Warns.

No. Override it, then call StartDeath / FinishDeath.

UGCS_AttackResultProcessor_GameplayEvent

Sends events on a server pawn or locally controlled pawn. Payload DynamicTags merge into Instigator Tags.

Yes for hit-stun and combo-advance events.

UGCS_AttackResultProcessor_GameplayCue

Executes cues locally; they do not replicate again with the result. Can replace its list from the attack definition and fill magnitudes from TaggedValues.

Yes for hit flashes and impact audio.

Failure signals: bEditorDebugEnabled off skips the processor in PIE. VeryVerbose VLog writes “Skipped local predicted / server only processor.”

ExecutePolicy contract

HandleAttackResult uses the policy to decide whether this result may enter a processor. The predicting context comes from bIsPredictingContext on the payload.

Policy

When it runs

What belongs here

What does not

Default

Non-predicting results, on every relevant machine.

Events after authoritative settlement, state reads that must match on both ends.

One-shot spends or death. If the GE predicted, the predicted pass is skipped and the authoritative result runs later.

LocalPredicted

The local predicted result, plus authoritative results that did not match a PredictionKey. A match (bWasPredicated) skips it.

Hit stall, local cues, camera shake.

Health, inventory, save data. Predicted bullets do not produce a predicted AttackResult, so this policy cannot settle them.

ServerOnly

Non-predicting, non-replicated authoritative results.

Combat logs, stats, drops.

Presentation the client must see immediately.

When a melee Instant GE has UGCS_GEComponent_PredictivelyExecute, AutonomousProxy writes PredictionKey and Executes locally. When the authoritative result replicates, the container marks the replicated entry bWasPredicated with the same key. If a Cue processor must play immediately, use LocalPredicted and treat bPredictGameplayCues carefully so the authoritative pass does not stack a second play.

Combat Flow hooks

UGCS_CombatFlow is one pipeline per actor, spawned on the authority and replicated. The combat component registers itself as a GGA Globals receiver in BeginPlay and forwards PreApply to the flow.

Entry

What it can change

When the default is enough

HandlePreGameplayEffectSpecApply

Append dynamic AssetTags to the upcoming spec (OutDynamicTagsAppendToSpec).

Attack-definition AttackTags already filter processors.

HandleGameplayEffectExecute

Build an FGCS_AttackResult from FGGA_GameplayEffectModCallbackData and RegisterAttackResult.

Not enough. The base implementation is empty. A project flow must produce the result here, or processors never see a hit. Local predicted execution also enters when the predictive-execute component is present.

HandleAttackResult

Dispatch by ExecutePolicy. The default already merges DynamicTags and writes the LastProcessed cache.

Enough. Do not copy another dispatcher just to run processors.

RegisterAttackResult accepts authority or a predicting context only. A client result that is neither is rejected with a Warning.

Do not Apply a new GE from PreApply, or you re-enter the Globals receiver. Do not hand-write AttackResults in the bullet layer. Keep the attack-definition handle on EffectContext and let the attribute callback return to this pipeline.

Combo ability hooks

UGCS_ComboAbility owns combo progression. Child attack abilities should not write ComboStep unless they deliberately bypass this contract. Selection runs on the locally controlled machine.

Entry

What it can change

When the default is enough

AllowAdvanceCombo

A false return makes AdvanceCombo return immediately. Default true.

No “cannot cancel out of hit-stun” rule.

StartCombo

Runs the first step from the incoming event. Default goes to HandleComboExecution.

No extra camera or weapon swap on opener.

AdvanceCombo

Asks AllowAdvanceCombo, then selects.

Input buffering already lives on the ability or input layer.

ResetCombo

Clears DesiredComboStep and calls ResetComboState. Invoked when the ability ends.

Clearing to zero is enough.

CanSelectedComboDefinition

Veto a row after table filters. Default true. Can read Extension.

EventTag / TagQuery / activation tests on the row are enough.

A good custom case: CanSelectedComboDefinition reads a required weapon tag from the row Extension and compares it to GetWeaponTags on GetCurrentWeapon, so a gun stance cannot pick the next sword hit.

Failure signals: a missing combo table Errors. No matching row is Verbose-only and sets DesiredComboStep = INDEX_NONE. A failed child TryActivateAbility Resets the string. When bAbortIfActivationTestFailed is true, one CanActivate failure aborts the whole combo and does not try later rows.

OnComboStepChanged

UGCS_CombatSystemComponent replicates ComboStep (SkipOwner). Local UpdateComboStep RPCs the other side; the replication callback fires on SimulatedProxy. After the step actually changes, the Blueprint hook OnComboStepChanged(PrevComboStep) runs and OnComboStepChangedEvent broadcasts.

Use it to switch an anim-graph layer or show “hit 2 / 3” in UI. Do not select the next move here — selection belongs on the combo ability. ResetComboState writes 0 only when the step is not already 0.

Verify

  1. Offline hit: Gameplay Debugger Attack Result shows a new entry, and Default Event / Cue processors each run once.
  2. Melee prediction: AutonomousProxy sees the LocalPredicted cue first; the same processor does not run again after the authoritative result. VeryVerbose VLog shows Skipped.
  3. Bullets: the client has trajectory only; the server has the Result. Do not hang predictive-execute on a bullet GE and expect local settlement.
  4. Combo: after the input event, ComboStep goes from 0 to 1. A finisher’s bResetComboStep returns to 0 only when MinComboStep > 0.