How-To: Filter Which Pops a Player Sees (Optional)

Goal: decide which numbers reach the screen - your own output, an ally's, an enemy's, healing, distant hits - and let the player change that choice. Visibility is authored as an ordered chain of rules in a data asset, not a fixed list of toggles, so you can delete, reorder, retune or add rules without touching code.

Prerequisites
You completed Quick Start. Leave the registry's FilterSet unset and nothing is ever filtered - this page is entirely optional.

1. Create the filter set

Content Browser right-click > Crimson > Combat Text > Filter Set. Name it DA_CrimsonCombatTextFilters, then point your style registry's Filter Set at it. A new asset seeds itself with the seven built-in rows below; the Add Built-In Filters button repopulates it if you clear it.

UCrimsonCombatTextFilterSet with the seven seeded rows, and DefaultResult set to Hide.
Verify
Pops behave as before: you see your own and your allies' output, everything that hits you, and nothing beyond 3000cm.

2. Read the chain

Rows are evaluated top to bottom. The first row that returns a verdict other than Ignore wins; anything no row describes falls through to the set's DefaultResult (Hide).

Order is the policy
"You always see what hits you" is not special-cased anywhere in code - it is a row sitting above the rows about other people's output. Move ShowIncoming below CritsOnly and a non-critical hit on your character stops showing. Reordering is a behavior change, and that is the point.
#RowDefaultEffect
0Distanceon, 3000cmHides text further than the slider from you. Events aimed at you are exempt
1ShowHealsonHealing, decided before anything looks at who cast it
2ShowIncomingonWhat happens to your character
3CritsOnlyoffWhen on, hides everything that is not a critical hit
4ShowOwnEffectsonDamage and healing you cause
5ShowAllyEffectsonDamage and healing your allies cause
6ShowEnemyEffectsoffWhat enemies do to someone other than you
Retune the tag rows for your project
ShowHeals and CritsOnly are written against Damage.Heal and Damage.Result.Crit. If your damage taxonomy names those differently, open the two rows and edit their Query - the plugin does not own your tags. An empty query matches nothing, so a mismatched row is inert rather than destructive.

3. Understand the two verdicts

A row does not decide show-or-hide. It answers Matches - does this rule describe this event? - and the chain then applies `MatchResult` when the player has the row switched on, or `DisabledResult` when they have it off.

That split is what makes the chain work as a user setting. A disabled ShowHeals row has to hide healing; if switching it off merely skipped the row, a heal you cast would fall through to ShowOwnEffects and appear anyway. Two shapes cover almost everything:

IntentMatchResultDisabledResult
"Show X" - switching it off actively hides XShowHide
A restriction - switching it off lifts itHideIgnore

4. The three built-in rule classes

All seven default rows are instances of just three classes. Add a row and pick one of these before reaching for code.

ClassMatches whenKey properties
UCrimsonCombatTextFilter_RelationshipThe actor in Role is one of the relationships in RelationshipMask. Both sides are normalized to the avatar pawn first, so a player's own output reads as SelfRole (Instigator / Target), RelationshipMask (Self / Ally / Enemy / Unknown), bRequireViewerIsNotOtherRole
UCrimsonCombatTextFilter_TagQueryQuery matches the event's context tagsQuery - a full FGameplayTagQuery, so ANY / ALL / NOT all work
UCrimsonCombatTextFilter_DistanceThe event is further from you than the row's scalarbExemptWhenViewerIsTarget, plus the scalar (default 3000cm)
Verify
Duplicate the ShowAllyEffects row, set its RelationshipMask to Ally and Enemy, and delete the original two. One row now covers both, and the settings screen shows one toggle instead of two.

5. Where the player's choices live

UCrimsonCombatTextPlayerSettings on the local PlayerController holds FilterEnabledOverrides and FilterScalarOverrides, both keyed by FilterId. A row with no entry uses its own bEnabledByDefault / ScalarDefault. Settings are local-only and never replicate.

PlayerController Blueprint -> Add Component -> Crimson Combat Text Player Settings, then Set Filter Enabled / Set Filter Scalar from your options UI.
Persistence
The component does not save itself. On the full stack, How-To: Expose Pop Options as User Settings persists every row automatically; standalone, write the two maps through your own save path.

6. Why did that number not appear?

Once a project authors its own chain, guessing gets expensive. The dev tools Filters tab lists the loaded chain in evaluation order and its decision trace names the row that decided a given event, whether that row was on or off, and the relationships it saw. Run Crimson.CombatText.DevTools in PIE.

Verify
On the Spawn tab pick a target and instigator, then click Test current Spawn tab event on the Filters tab. The trace line names the deciding row - the fastest way to tell "my chain is wrong" from "my team hook is wrong".

See also

  • How-To: Write Your Own Filter - a rule the three built-in classes cannot express.
  • How-To: Bind Your Team System - make Self / Ally / Enemy mean something.
  • How-To: Expose Pop Options as User Settings - drive the chain from a saved options menu.
  • Concept: Event Flow & Replication - where in the pipeline the chain runs.