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 |
Branch settlement on source / target tags | Queries already exist | |
Append dynamic tags before a GE applies | Empty base implementation | |
Turn an attribute callback into an AttackResult | Empty base; project must fill it | |
Combo gates, extra selection rules | Default allows every advance | |
Drive an anim layer or UI from the step | Component already broadcasts | |
Immediate local melee hit feedback | Component already exists | Add |
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? |
|---|---|---|
| Placeholder. Native Handle is empty; first call Warns. | No. Override it, then call |
| Sends events on a server pawn or locally controlled pawn. Payload | Yes for hit-stun and combo-advance events. |
| Executes cues locally; they do not replicate again with the result. Can replace its list from the attack definition and fill magnitudes from | 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 |
|---|---|---|---|
| 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. |
| The local predicted result, plus authoritative results that did not match a PredictionKey. A match ( | Hit stall, local cues, camera shake. | Health, inventory, save data. Predicted bullets do not produce a predicted AttackResult, so this policy cannot settle them. |
| 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 |
|---|---|---|
| Append dynamic AssetTags to the upcoming spec ( | Attack-definition |
| Build an | 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. |
| Dispatch by ExecutePolicy. The default already merges | 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 |
|---|---|---|
| A false return makes | No “cannot cancel out of hit-stun” rule. |
| Runs the first step from the incoming event. Default goes to | No extra camera or weapon swap on opener. |
| Asks | Input buffering already lives on the ability or input layer. |
| Clears | Clearing to zero is enough. |
| Veto a row after table filters. Default true. Can read | 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
- Offline hit: Gameplay Debugger Attack Result shows a new entry, and Default Event / Cue processors each run once.
- Melee prediction: AutonomousProxy sees the LocalPredicted cue first; the same processor does not run again after the authoritative result. VeryVerbose VLog shows Skipped.
- Bullets: the client has trajectory only; the server has the Result. Do not hang predictive-execute on a bullet GE and expect local settlement.
- Combo: after the input event, ComboStep goes from 0 to 1. A finisher’s
bResetComboStepreturns to 0 only whenMinComboStep > 0.