Quick Start
By the end of this page, a server-side broadcast makes a floating combat text appear over a target actor on every client - styled by your registry and recycled through the widget pool.
Damage and its children, e.g. Damage.Type.Fire).DA_CrimsonCombatTextStyles), a pop widget (WBP_CrimsonCombatText), and a distance curve - and DefaultCrimsonCombatText.ini already points Project Settings at them. So a fresh install pops numbers as soon as you wire the GameState component and broadcast (steps 5-6). Steps 2-4 show how to author and assign your own assets - skip them to try the shipped defaults first.Authoring your own registry? Its editor's Add Examples button fills it with a worked set of styles, modifiers and advanced rules using tags the plugin ships, so you can read one instead of inventing one - see How-To: Author Styles in the Registry Editor.
1. Enable the plugin
Open Edit -> Plugins, type Crimson in the search box, tick CrimsonCombatText's checkbox, and restart the editor when prompted. For a Blueprint project that's the entire install - you never hand-edit the .uproject or any .Build.cs.
2. Create the motion set and style registry
Two data assets. Content Browser right-click > Crimson > Combat Text:
- Motion Set - name it
DA_CrimsonCombatTextMotions. It arrives pre-seeded with ten editable built-in presets, so it is usable immediately. - Style Registry - name it
DA_CrimsonCombatTextStyles. Set itsMotionSetto the asset above.
DA_CrimsonCombatTextStyles (/CrimsonCombatText/) - study its Styles map (one row per tag, each with a MotionPreset), its Modifiers map, and its MotionSet pointing at DA_CrimsonCombatTextMotions in the same folder. Duplicate the pair as your starting point.Plugin content is hidden in the Content Browser until you tick Settings -> Show Plugin Content.
In the registry, add a row to `Styles` keyed by the tag your gameplay code will send - Damage is the obvious first one. Set its MotionPreset to CrimsonCombatText.Motion.ArcOut and leave everything else at default.
Styles resolves hierarchically: a hit tagged Damage.Fire.Burn falls back to Damage.Fire, then Damage, then DefaultStyle. You only author the specificity you care about - one Damage row already covers every damage type.Crit modifier layers onto whichever style matched, so you never need Damage.Fire.Crit and Damage.Ice.Crit as separate entries.MotionSet field resolves to your motion set (not None), and the Styles map lists your Damage row with MotionPreset = CrimsonCombatText.Motion.ArcOut.3. Create the combat text widget
Content Browser right-click > Crimson > Combat Text > Combat Text Widget, named WBP_CrimsonCombatText. Add a Rich Text Block and name it TextBlock to get formatted text for free.
The widget's base class recognizes two child widgets by name. Name them exactly as written or the bind does not happen:
| Widget name | Palette type | What the plugin does with it |
|---|---|---|
TextBlock | Rich Text Block | Receives the formatted text every time the widget is taken from the pool |
TextBorder | Border | Never touched by the system - a styling hook you drive yourself |
WBP_CrimsonCombatText (/CrimsonCombatText/) - its hierarchy is exactly the table above: a Border named TextBorder wrapping a Rich Text Block named TextBlock, with a Text Style Set assigned on the rich text. Duplicate it as your starting point.TextBlock and TextBorder binds are optional. Bind nothing and implement the On Combat Text Applied event instead if you would rather drive your own visuals.ValueStyleTag / PrefixStyleTag (Default out of the box). Without them the text renders unstyled.TextBlock exactly (no trailing digit from a duplicate), and its Text Style Set resolves to a Data Table.4. Point Project Settings at your assets
Open Project Settings -> Crimson -> Crimson Combat Text. If you used the asset names above these are already correct; otherwise set them:
| Setting | Value |
|---|---|
RegistryPath | Your style registry (step 2) |
WidgetClassPath | Your widget Blueprint (step 3) |
RendererClass | Leave as the widget renderer |
NumberFormat | CommaSeparated, Abbreviated or Raw |
RegistryPath and WidgetClassPath both resolve to real assets (neither reads None), and the values are written to your project's Config/DefaultCrimsonCombatText.ini under [/Script/CrimsonCombatText.CrimsonCombatTextSettings].5. Add the replication component to your GameState
UCrimsonCombatTextReplicationComponent is the broadcast entry point. It must live on the GameState (replicated, exists on every client) - it registers itself with each client's subsystem on BeginPlay, so there is no manual wiring.
Open your GameState Blueprint. In the Components panel click + Add, type combat text, and pick Crimson Combat Text Replication Component. There is no graph work - the component finds the local subsystem itself on BeginPlay.
If your project has no GameState Blueprint yet: Content Browser -> right-click -> Blueprint Class -> Game State Base, then set it as Game State Class on your GameMode Blueprint.
6. Broadcast a pop from the server
Wherever damage or healing is applied on the server, build a FCrimsonCombatTextEvent and call Broadcast Combat Text. Set Target (the hit actor - the server resolves the pop's world location from it) and Tags (matched against your registry rules and the per-player filters). Instigator, PrefixText, and CustomText are optional.
In whatever Blueprint applies damage or healing, on the branch that runs on the server: Has Authority (Branch, True) -> Get Game State -> Get Component by Class (Component Class = Crimson Combat Text Replication Component) -> Broadcast Combat Text.
Feed the Broadcast Combat Text node's Event pin from a Make CrimsonCombatTextEvent node (drag off the pin and search Make CrimsonCombatTextEvent): Value = the amount, Target = the hit actor, Tags = the tag your registry row is keyed by in step 2 (Damage), Instigator = whoever dealt it. Leave PrefixText, CustomText and World Location alone - the server resolves the location from Target.
BroadcastCombatText validates HasAuthority() and ignores (with a warning) calls made on a client - safe to call from code that runs on both sides. In singleplayer and on listen servers the local player is also a client of the multicast, so this same path works everywhere.When you want text somewhere else - under the enemy for healing, in a fixed HUD area, next to a health bar - see How-To: Position Pops and How-To: Show Pops on the HUD or a Health Bar.