Interaction Integration

CrimsonCore is where the abstract CrimsonInteraction system becomes a working interaction loop. The integration ships:

  • UCrimsonCoreGameplayAbility_Interact — concrete persistent scan + dispatch ability. Picks between top-down and forward-line-trace strategies, binds two input tags (quick-press + context-menu), broadcasts Message.Interaction.OptionsChanged for HUD widgets. Prompt presentation is switchable via PromptMode (on-actor world indicators by default).
  • UCrimsonCoreGameplayAbility_InteractionDuration — thin subclass that defaults the UIExtension slot + success tag and forwards NotifyInteractionSuccess to the target on completion. Not abstract: assign it directly as an option's InteractionActionAbility for a working default channel. Channels are press-and-forget; opt-in cancels: MaxDistanceFromTarget (walk-away, default 600) and bCancelWhenInputReleased (hold-to-mine).
  • UCrimsonCoreGameplayAbility_InteractionHandler — fire-and-forget handler ability; default PickupHandlerAbility on pickups.
  • FCrimsonInteractionOptionsChangedMessage — broadcast struct so the prompt widget can listen without coupling to the ability.
  • Collision channel Crimson_TraceChannel_Interaction + profiles Interactable_OverlapDynamic / Interactable_BlockDynamic (host project's DefaultEngine.ini).
  • Native tags InputTag.Interact, InputTag.Interact.OpenMenu, HUD.Interaction.Prompt, HUD.Interaction.Progress, Ability.Interaction.SuccessEvent.Default, Message.Interaction.OptionsChanged.

Quick-press vs context menu

Two input bindings on the same persistent ability: quick-press fires Options[0] immediately (Diablo / PoE pickup feel); OpenMenu opens a world-anchored context menu listing every available option via UCrimsonCoreContextMenuSubsystem::ShowContextMenuForActor. If only one option exists, OpenMenu falls through to the quick-press path so single-option pickups don't show a useless one-row menu.

cpp
// BP defaults on BP_GA_Interact:
InputTag = InputTag.Interact; // quick-press -> Options[0]
ContextMenuInputTag = InputTag.Interact.OpenMenu; // right-click / F -> context menu
ContextMenuWidgetClass = WBP_ContextMenu_World; // optional: unset falls back to
// UCrimsonUISettings::DefaultWorldContextMenuClass

Multi-action pickups

ACrimsonCorePickupActor::SecondaryActions is a TArray<FCrimsonPickupSecondaryAction> exposed in Blueprint defaults. Each entry produces an extra FCrimsonInteractionOption in GatherInteractionOptions, so designers can add Split Stack, Drop Here, Inspect, etc. without C++. The primary pickup action stays as Options[0]; secondaries are Options[1..N] and reachable only through the OpenMenu input.

cpp
USTRUCT(BlueprintType)
struct FCrimsonPickupSecondaryAction
{
UPROPERTY(EditDefaultsOnly) FText Label;
UPROPERTY(EditDefaultsOnly) FText SubText;
UPROPERTY(EditDefaultsOnly) TSubclassOf<UGameplayAbility> HandlerAbility;
};

Each HandlerAbility should be a subclass of UCrimsonCoreGameplayAbility_InteractionHandler (or any ability that triggers on Ability.Interaction.Activate and reads TriggerEventData->Target).

Prompt widget — more-options hint

UCrimsonCoreInteractionPromptWidget has two optional BindWidgetOptional slots: MoreOptionsContainer (a UWidget wrapper — usually a horizontal box with a label + action widget) and MoreOptionsActionWidget (a UCrimsonActionWidget). Set OpenMenuInputAction in Class Defaults to your IA_Interact_OpenMenu. The container auto-shows only when more than one option is available, so simple pickups stay uncluttered.

Prompt widget - progress ring around the input key

No extra widget is needed: UCommonActionWidget already ships a progress layer behind the key icon. On the prompt widget's bound ActionWidget, set Progress Material Brush to a radial-fill material and Progress Material Param to its 0..1 scalar parameter - hold and duration-channel progress then renders as a ring around the input key, with no separate progress HUD element. The prompt widget drives the layer via OnActionProgress / OnActionComplete from Message.Interaction.Progress, filtered to the owning pawn (so it is multiplayer-safe on listen servers). For fully custom display, implement the On Interaction Progress event (or read CurrentProgress01).

Radial-fill material in one node
A minimal radial-fill material: RadialGradientExponential (or a SphereMask on VectorToRadialValue) compared against a scalar parameter, output to Opacity in a UI material domain. Set it as the ActionWidget's Progress Material Brush and name the parameter in Progress Material Param - the action widget creates the dynamic instance itself. Note: CommonUI only shows this layer for actions it classifies as holds (Enhanced Input Hold triggers); UCrimsonActionWidget also shows it whenever a progress material is authored, since Crimson holds are ability-timer driven on trigger-less actions.

Setup steps

  • Create a Blueprint subclass of UCrimsonCoreGameplayAbility_Interact. Set ScanStrategy (TopDown or SingleLineTrace), trace profiles, scan rate/range, and the InputTag (defaults to InputTag.Interact).
  • Add the ability to a UCrimsonAbilitySet granted on pawn spawn — auto-activates via OnAvatarSet/OnGiveAbility (Lyra passive pattern).
  • In your UCrimsonInputConfig, map InputTag.Interact to an IA_Interact Enhanced Input action.
  • On each interactable object (pickup, door, NPC), implement ICrimsonInteractableTarget::GatherInteractionOptions. Set InputType = Instant for press, or Hold + InputHoldDuration, or set InteractionActionAbility (your UCrimsonCoreGameplayAbility_InteractionDuration subclass) for a channeled interaction.
  • Configure the interactable's overlap component on the Interactable_OverlapDynamic profile so the scan trace finds it.

Collision channel + profiles

Project-level config required
UE5 caches UCollisionProfile before plugin configs mount, so the channel + profiles must live in the host project's Config/DefaultEngine.ini — not the plugin's. Copy the block from the CrimsonCore README. The plugin logs LogCrimsonCore warnings on startup if the profiles aren't found.

Interactable_OverlapDynamic is set on ACrimsonCorePickupActor::InteractionSphere; Interactable_BlockDynamic is for blocking surfaces that still let the interaction trace through. The custom trace channel Crimson_TraceChannel_Interaction claims ECC_GameTraceChannel18 (highest slot, picked so it rarely collides with project-defined channels — override in the project's ini if you already use slot 18).

Prompt presentation (PromptMode)

PromptMode on the interact ability picks how "you can interact" is shown to the local player:

ModeBehavior
World Indicator (default)Floats a widget over each interactable actor in range. Zero setup: the required UCrimsonIndicatorManagerComponent is added to the local player controller on demand, and the widget class resolves per option - InteractionWidgetClass on the option, else DefaultIndicatorWidgetClass, else DefaultInteractionWidgetClass.
HUD SlotPins the single prompt widget at the HUD.Interaction.Prompt extension slot (the previous default). Needs a CrimsonUIExtensionPoint at that tag in your HUD layout.
BothWorld indicators plus the HUD prompt.
CustomNo built-in prompt. Override the PresentInteractionPrompt (activation), UpdateInteractionPrompt (options changed), and DismissInteractionPrompt (ability end) events - Blueprint or C++ - to supply your own UI.
Cleanup is automatic
The built-in paths (HUD extension handle, world indicators) are always cleaned up natively when the ability ends, regardless of mode or overrides. A Custom override only needs to tear down UI it created itself, in DismissInteractionPrompt.

HUD widgets

Extension-point slots are only needed for the paths you opt into: HUD.Interaction.Prompt when PromptMode is HUD Slot or Both (the pinned prompt widget listens on Message.Interaction.OptionsChanged to show/hide itself), and HUD.Interaction.Progress only when a duration ability sets ActionWidgetClass (it then auto-registers its progress widget there via UCrimsonUIExtensionSubsystem). The progress ring on the prompt widget's ActionWidget covers hold/channel progress with no extension slot at all.

Source locations
Concrete abilities: Plugins/CrimsonCore/Source/CrimsonCore/Public/Abilities/Interaction/. Message struct: Public/Abilities/Interaction/CrimsonInteractionOptionsChangedMessage.h. Tags: Public/CrimsonCoreTags.h. Abstract bases + scan tasks: Plugins/CrimsonInteraction/Source/CrimsonInteraction/Public/.