Skip to content

Gameplay Cue Visuals

Summary: Persistent cosmetic visuals — buff auras and elemental weapon effects — are driven entirely by GameplayCues that ride a GameplayEffect's lifecycle (no custom RPCs). Data assets describe the visual layers, thin Blueprint children bind cue tags to those configs, and a small set of AGameplayCueNotify_Actor handlers spawn/tear down the layers on every client. This document explains that framework and how it differs from one-shot impact FX.


Table of Contents


Architecture Overview

Two families of persistent cosmetic VFX share one pattern: a GameplayEffect (a buff for auras, an equip state for weapons) declares a GameplayCue.* tag; the cue notify spawns visual layers WhileActive and removes them OnRemove. Because cue replication is built into GAS, every client sees the effect with no bespoke networking.

                        AURAS                                  WEAPON EFFECTS
            +-----------------------------+         +-----------------------------------+
            | Buff GameplayEffect          |         | Server: weapon equipped            |
            | (e.g. Haste) has cue tag     |         | EquipmentComponent derives identity|
            | GameplayCue.Aura.*           |         | from granted UOnHitAbility  |
            +--------------+--------------+         |   StatusTag                        |
                           |                         +----------------+------------------+
                           | GE active/removed                        | StatusTag -> registry
                           v                                          v
            +-----------------------------+         +-----------------------------------+
            | AGameplayCueNotify_Aura      |         | Fires GameplayCue.Weapon.* on ASC  |
            | (one BP child per aura tag)  |         | cue params carry the equipment slot|
            +--------------+--------------+         +----------------+------------------+
                           |                                          | (replicated to all clients)
                           | reads UAuraVisualConfig                  v
                           v                         +-----------------------------------+
            +-----------------------------+         | AGameplayCueNotify_Weapon          |
            | Spawn enabled layers:        |         | (single notify at PARENT tag)      |
            |  1. ground deferred decal    |         | resolves child tag + slot ->       |
            |  2. body overlay material    |         | UWeaponEffectsConfiguration entry  |
            |  3. flourish Niagara         |         | -> spawn at FX_Weapon socket       |
            +-----------------------------+         +-----------------------------------+

Core Concepts (Why)

  • Cue-driven, not RPC-driven. Visual state is a function of GAS state. Spawning on WhileActive / OnActive and cleaning up on OnRemove means replication, late-join, and teardown all come for free from the GameplayEffect/cue lifecycle. No replicated visual booleans, no multicast RPCs.

  • Data-driven, no per-effect C++. Adding an aura or a weapon element is content work: a data asset (the visual layers) plus a Material Instance / Niagara plus one tag mapping. The C++ notify classes are generic.

  • Aura visuals are deliberately power-agnostic. Color, pulse, and radius are baked into the chosen Material Instance, not attribute-driven. A stronger Haste does not glow brighter. This keeps auras readable and avoids coupling cosmetics to balance numbers — see UAuraVisualConfig, which intentionally exposes no color/intensity fields.

  • Distinct from one-shot impact FX. This layer is for persistent cosmetics. One-shot hit reactions (FCombatEffectConfig via the combat-impact cue) and animation-driven swing trails are separate systems. The damage-number cue (AGameplayCueNotify_DamageNumber, see Damage Execution) is the closest sibling pattern: same GameplayCueNotify_Actor base, but transient and execute-once rather than active/removed.


Aura Visuals

An aura is described by a UAuraVisualConfig data asset exposing three independent, optional layers. Each aura enables any subset; a new aura is one config asset + one Material Instance + one thin AGameplayCueNotify_Aura Blueprint child that sets GameplayCueTag (a GameplayCue.Aura.* tag) and points at the config.

Layer What it is Notes
Ground decal Deferred decal projected downward (the M_Aura_Decal MI family) Box conforms to terrain; offset below the feet so it projects onto the ground, not the head. Receiver-normal angle-fade prevents the decal climbing walls. The notify disables decal receipt on the owner's own meshes so the aura stays on the floor.
Body overlay Overlay material applied to every visible mesh on the owner "This unit is buffed" rim-glow. GatherVisibleBodyMeshes skips bHiddenInGame / !IsVisible() components — notably the hidden ALS driver mesh — and skips meshes socketed under another mesh (weapons, props), since the aura is a body effect. Each affected mesh's prior overlay is saved and restored (see below).
Flourish Persistent Niagara attached to the owner Motes / runes; optional attach socket.

AGameplayCueNotify_Aura spawns only the enabled layers in OnActive and tears them all down in OnRemove. Spawned handles are tracked transiently because cue notify instances may be pooled and reused.

The Overlay Slot Is Shared and Single-Valued

SetOverlayMaterial is one slot per mesh — writing it discards whatever was there. That slot is not the aura's to own: enemy meshes already carry a rim-light overlay for dark-zone readability, and a naive aura would delete it permanently the first time it ran.

So the notify treats the slot as borrowed. On spawn, each mesh's existing overlay is recorded in an FAuraOverlayTarget (mesh + previous material) before SetOverlayMaterial; teardown walks that list and writes each previous material back. An aura therefore suspends a pre-existing overlay for its duration and never clobbers it.

Two consequences worth knowing: - Overlapping auras don't compose. The last one applied wins visually, and unwinding is LIFO-correct only if they tear down in reverse order. Design auras so two rarely stack on the same unit. - Anything else writing the overlay slot mid-aura is lost on teardown, since the notify restores the value it captured at spawn.

See Character Rim Overlay for the other occupant of this slot.


Elemental Weapon Visuals

A weapon's cosmetic identity is derived from its gameplay identity rather than authored directly: the element a weapon visually expresses is the on-hit status it grants (a bleed weapon drips blood).

Server derivation. When a weapon is equipped, UEquipmentComponent inspects the weapon's granted UOnHitAbilitys for their StatusTag, looks each up in the UWeaponEffectsConfiguration registry to find the matching GameplayCue.Weapon.* tag and priority, and fires the top-N cues (N = MaxSimultaneousEffects, by priority) on the wielder's ASC. The fired cue's parameters carry the equipment slot tag so the right weapon mesh can be found. On unequip, the previously fired cues for that slot are removed.

Client handling. A single AGameplayCueNotify_Weapon is registered at the parent GameplayCue.Weapon tag (one thin BP child), so it handles every GameplayCue.Weapon.* child. On the cue it resolves the specific child tag and the slot tag from the cue params, looks up the registry entry, finds the wielder's weapon mesh for that slot via the PlayerState's equipment component, and spawns the configured Niagara/overlay at the entry's socket (default FX_Weapon). Visible to all players.

Registry. UWeaponEffectsConfiguration maps GameplayCue.Weapon.*FWeaponEffectConfig (Niagara, optional overlay material, socket, the StatusTag it represents, and a priority). The stateless cue notify has no owning component, so it reaches the registry through the UWeaponEffectsSettings developer-settings singleton (Project Settings → Game → Weapon Effects) — the same singleton pattern the combat-impact cue uses.


Replication & Lifecycle

GE applied (server) ──► cue replicated ──► OnActive on each client ──► spawn layers
GE removed  (server) ──► cue replicated ──► OnRemove on each client ──► teardown layers
Concern How it's handled
Networking Inherent in GAS cue replication — no custom RPCs.
Cue-vs-equipment race On clients the GameplayCue.Weapon.* cue can arrive before the equipment meshes finish spawning (separate replication path). AGameplayCueNotify_Weapon retries the mesh lookup for a bounded window.
Pooled notifies Cue notify instances may be pooled/reused, so spawned handles are tracked transiently and the weapon notify also tears down in EndPlay as a safety net (a recycled instance may never receive OnRemove).

Public Contracts

UAuraVisualConfig (data asset)

Field group Purpose
Decal (bUseDecal, DecalMaterial, DecalSize, DecalOffset) Ground deferred-decal layer; size/offset are fixed per-aura geometry, not attribute-driven.
Overlay (bUseOverlay, OverlayMaterial) Body overlay layer.
Flourish (bUseFlourish, FlourishNiagara, FlourishSocketName) Persistent Niagara layer.

No color/pulse/radius fields by design — those are baked into the Material Instance.

UWeaponEffectsConfiguration (registry data asset)

Method Parameters Purpose
GetEffectForCueTag CueTag Client hot path: config for a GameplayCue.Weapon.* tag (nullptr if unmapped).
FindCueForStatus StatusTag, out CueTag, out Priority Server derivation: cue tag + priority whose entry represents an OnHit status.

UEquipmentComponent (weapon-identity driving)

Method Parameters Purpose
TriggerWeaponIdentityCues Fragment, SlotTag, ASC Server: derive identities, map to cues, fire top-N on the wielder's ASC.
RemoveWeaponIdentityCues SlotTag, ASC Server: remove the cues previously fired for a slot.

Cue notify handlers

Class Registered at Role
AGameplayCueNotify_Aura One BP child per GameplayCue.Aura.* Spawns enabled UAuraVisualConfig layers OnActive, tears down OnRemove.
AGameplayCueNotify_Weapon Parent GameplayCue.Weapon (one BP child) Resolves child tag + slot, looks up registry, spawns at weapon socket; bounded retry for the mesh race.

Source References

Component Location
UAuraVisualConfig Source/ProjectEternal/Public/AbilitySystem/Auras/AuraVisualConfig.h
AGameplayCueNotify_Aura Source/ProjectEternal/Public/AbilitySystem/GameplayCues/GameplayCueNotify_Aura.h
AGameplayCueNotify_Weapon Source/ProjectEternal/Public/AbilitySystem/GameplayCues/GameplayCueNotify_Weapon.h
UWeaponEffectsConfiguration / FWeaponEffectConfig Source/ProjectEternal/Public/Combat/Data/WeaponEffectsConfiguration.h
UWeaponEffectsSettings Source/ProjectEternal/Public/Combat/Data/WeaponEffectsSettings.h
UEquipmentComponent::TriggerWeaponIdentityCues Source/ProjectEternal/Public/EquipmentManagement/Components/EquipmentComponent.h
UOnHitAbility (StatusTag source) Source/ProjectEternal/Public/Abilities/OnHitAbility.h

  • Damage ExecutionAGameplayCueNotify_DamageNumber, the sibling transient cue pattern; on-hit ability StatusTag.
  • Ability ClassesUOnHitAbility that defines a weapon's gameplay identity.
  • GAS Overview — GameplayEffect/cue lifecycle these visuals ride on.
  • Character Rim Overlay — the enemy-readability material sharing the same single-valued mesh overlay slot.

Recent Changes

Date Change Impact
2026-08-06 Carnage aura shipped content-only DA_Aura_Carnage + MI_Overlay_Aura_Carnage + a GC_Aura_Carnage notify child — no C++ changes, confirming the "adding an aura is content work" claim above
2026-08-06 Overlay applies to all visible meshes; prior overlay saved/restored GatherVisibleBodyMeshes covers every visible body mesh instead of one, skipping the hidden ALS driver mesh and socketed props; FAuraOverlayTarget records each mesh's previous overlay and teardown restores it, so an aura no longer permanently destroys the enemy rim-light overlay
2026-05-25 Aura & elemental weapon VFX framework New GameplayCue-driven persistent cosmetics: UAuraVisualConfig + AGameplayCueNotify_Aura (data-driven 3-layer auras), AGameplayCueNotify_Weapon + UWeaponEffectsConfiguration/UWeaponEffectsSettings (weapon element derived from OnHit StatusTag). No custom RPCs; equipment component drives weapon identity cues.